@anuma/sdk 9.1.4 → 9.1.6

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.
@@ -723,6 +723,12 @@ function assertTransportMatchesEndpoint(transport, endpoint) {
723
723
  `endpointOverride "${endpoint}" is the other transport's endpoint, but transport is "${transport}". The request body is built for the transport, so this sends the wrong shape and 400s without retry.`
724
724
  );
725
725
  }
726
+ var TIME_BUDGET_EXHAUSTED = {
727
+ kind: "terminal",
728
+ code: "time-budget-exhausted",
729
+ reason: "time budget exhausted"
730
+ };
731
+ var MAX_TIMER_DELAY_MS = 2147483647;
726
732
  var RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
727
733
  function isRetryableStatus(status) {
728
734
  return status >= 500 || RETRYABLE_HTTP.has(status);
@@ -778,7 +784,8 @@ async function callPortalJsonCompletion(req) {
778
784
  }
779
785
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
780
786
  const startedAt = Date.now();
781
- const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
787
+ const deadlineAt = req.totalTimeoutMs === void 0 ? void 0 : startedAt + req.totalTimeoutMs;
788
+ const overBudget = () => deadlineAt !== void 0 && Date.now() >= deadlineAt;
782
789
  let lastFailure;
783
790
  let reinforce = false;
784
791
  const giveUp = () => {
@@ -791,17 +798,11 @@ async function callPortalJsonCompletion(req) {
791
798
  lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
792
799
  break;
793
800
  }
794
- const attemptReq = req.totalTimeoutMs !== void 0 ? {
795
- ...req,
796
- timeoutMs: Math.max(
797
- 1,
798
- Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
799
- ),
800
- ...reinforce && { reinforceJsonContract: true }
801
- } : reinforce ? { ...req, reinforceJsonContract: true } : req;
801
+ const attemptReq = reinforce ? { ...req, reinforceJsonContract: true } : req;
802
802
  const outcome = await attemptPortalJson(
803
803
  { ...attemptReq, transport },
804
- endpoint
804
+ endpoint,
805
+ deadlineAt
805
806
  );
806
807
  if (outcome.kind === "ok") {
807
808
  req.onAttempt?.({ attempt, ok: true });
@@ -841,13 +842,38 @@ async function callPortalJsonCompletion(req) {
841
842
  }
842
843
  return giveUp();
843
844
  }
844
- async function attemptPortalJson(req, endpoint) {
845
+ async function attemptPortalJson(req, endpoint, deadlineAt) {
846
+ const controller = new AbortController();
847
+ if (deadlineAt === void 0 || deadlineAt - Date.now() > MAX_TIMER_DELAY_MS) {
848
+ return requestPortalJson(req, endpoint, controller);
849
+ }
850
+ const remainingMs = deadlineAt - Date.now();
851
+ if (remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
852
+ let timer;
853
+ try {
854
+ const outcome = await Promise.race([
855
+ new Promise((resolve) => {
856
+ timer = setTimeout(() => {
857
+ resolve(TIME_BUDGET_EXHAUSTED);
858
+ controller.abort();
859
+ }, remainingMs);
860
+ }),
861
+ requestPortalJson(req, endpoint, controller, deadlineAt)
862
+ ]);
863
+ return Date.now() >= deadlineAt ? TIME_BUDGET_EXHAUSTED : outcome;
864
+ } finally {
865
+ clearTimeout(timer);
866
+ }
867
+ }
868
+ async function requestPortalJson(req, endpoint, controller, deadlineAt) {
845
869
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
846
870
  const fetchImpl = req.fetchFn ?? fetch;
847
- const timeoutMs = req.timeoutMs ?? 6e4;
848
871
  const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
872
+ const remainingMs = deadlineAt === void 0 ? Infinity : deadlineAt - Date.now();
873
+ if (controller.signal.aborted || remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
849
874
  if (authHeaders === null)
850
875
  return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
876
+ const timeoutMs = Math.min(req.timeoutMs ?? 6e4, remainingMs);
851
877
  const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
852
878
  const prefill = usesPrefill ? "{" : "";
853
879
  const messages = [
@@ -857,7 +883,6 @@ async function attemptPortalJson(req, endpoint) {
857
883
  ];
858
884
  if (prefill) messages.push({ role: "assistant", content: prefill });
859
885
  const supportsJsonObjectFormat = supportsResponseFormat(req.model);
860
- const controller = new AbortController();
861
886
  const timer = setTimeout(() => controller.abort(), timeoutMs);
862
887
  const requestBody = req.transport === "responses" ? {
863
888
  model: req.model,
@@ -4,7 +4,7 @@ import {
4
4
  notifyConsolidationFallback,
5
5
  requiresResponsesTransport,
6
6
  resolvePiiRedactor
7
- } from "./chunk-XW3LYSDA.mjs";
7
+ } from "./chunk-WRZTH4OS.mjs";
8
8
  import "./chunk-GYKJOWEO.mjs";
9
9
 
10
10
  // src/lib/memory/consolidate.ts
@@ -875,7 +875,8 @@ async function callPortalJsonCompletion(req) {
875
875
  }
876
876
  const maxAttempts = Math.max(1, req.maxAttempts ?? 3);
877
877
  const startedAt = Date.now();
878
- const overBudget = () => req.totalTimeoutMs !== void 0 && Date.now() - startedAt >= req.totalTimeoutMs;
878
+ const deadlineAt = req.totalTimeoutMs === void 0 ? void 0 : startedAt + req.totalTimeoutMs;
879
+ const overBudget = () => deadlineAt !== void 0 && Date.now() >= deadlineAt;
879
880
  let lastFailure;
880
881
  let reinforce = false;
881
882
  const giveUp = () => {
@@ -888,17 +889,11 @@ async function callPortalJsonCompletion(req) {
888
889
  lastFailure = { reason: "time-budget-exhausted", attempts: attempt - 1 };
889
890
  break;
890
891
  }
891
- const attemptReq = req.totalTimeoutMs !== void 0 ? {
892
- ...req,
893
- timeoutMs: Math.max(
894
- 1,
895
- Math.min(req.timeoutMs ?? 6e4, req.totalTimeoutMs - (Date.now() - startedAt))
896
- ),
897
- ...reinforce && { reinforceJsonContract: true }
898
- } : reinforce ? { ...req, reinforceJsonContract: true } : req;
892
+ const attemptReq = reinforce ? { ...req, reinforceJsonContract: true } : req;
899
893
  const outcome2 = await attemptPortalJson(
900
894
  { ...attemptReq, transport },
901
- endpoint
895
+ endpoint,
896
+ deadlineAt
902
897
  );
903
898
  if (outcome2.kind === "ok") {
904
899
  req.onAttempt?.({ attempt, ok: true });
@@ -938,13 +933,38 @@ async function callPortalJsonCompletion(req) {
938
933
  }
939
934
  return giveUp();
940
935
  }
941
- async function attemptPortalJson(req, endpoint) {
936
+ async function attemptPortalJson(req, endpoint, deadlineAt) {
937
+ const controller = new AbortController();
938
+ if (deadlineAt === void 0 || deadlineAt - Date.now() > MAX_TIMER_DELAY_MS) {
939
+ return requestPortalJson(req, endpoint, controller);
940
+ }
941
+ const remainingMs = deadlineAt - Date.now();
942
+ if (remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
943
+ let timer;
944
+ try {
945
+ const outcome2 = await Promise.race([
946
+ new Promise((resolve) => {
947
+ timer = setTimeout(() => {
948
+ resolve(TIME_BUDGET_EXHAUSTED);
949
+ controller.abort();
950
+ }, remainingMs);
951
+ }),
952
+ requestPortalJson(req, endpoint, controller, deadlineAt)
953
+ ]);
954
+ return Date.now() >= deadlineAt ? TIME_BUDGET_EXHAUSTED : outcome2;
955
+ } finally {
956
+ clearTimeout(timer);
957
+ }
958
+ }
959
+ async function requestPortalJson(req, endpoint, controller, deadlineAt) {
942
960
  const baseUrl = req.baseUrl ?? defaultBaseUrl();
943
961
  const fetchImpl = req.fetchFn ?? fetch;
944
- const timeoutMs = req.timeoutMs ?? 6e4;
945
962
  const authHeaders = await resolvePortalAuthHeaders(req, req.tag);
963
+ const remainingMs = deadlineAt === void 0 ? Infinity : deadlineAt - Date.now();
964
+ if (controller.signal.aborted || remainingMs <= 0) return TIME_BUDGET_EXHAUSTED;
946
965
  if (authHeaders === null)
947
966
  return { kind: "terminal", code: "auth-unavailable", reason: "auth unavailable (no token)" };
967
+ const timeoutMs = Math.min(req.timeoutMs ?? 6e4, remainingMs);
948
968
  const usesPrefill = req.transport !== "responses" && req.model.startsWith("anthropic/");
949
969
  const prefill = usesPrefill ? "{" : "";
950
970
  const messages = [
@@ -954,7 +974,6 @@ async function attemptPortalJson(req, endpoint) {
954
974
  ];
955
975
  if (prefill) messages.push({ role: "assistant", content: prefill });
956
976
  const supportsJsonObjectFormat = supportsResponseFormat(req.model);
957
- const controller = new AbortController();
958
977
  const timer = setTimeout(() => controller.abort(), timeoutMs);
959
978
  const requestBody = req.transport === "responses" ? {
960
979
  model: req.model,
@@ -1139,7 +1158,7 @@ function extractResponsesContent(body) {
1139
1158
  const text14 = root.output.filter((item) => asRecord(item)?.type === "message").flatMap((item) => Array.isArray(item.content) ? item.content : []).map((part) => asRecord(part)?.text).filter((t) => typeof t === "string").join("");
1140
1159
  return text14;
1141
1160
  }
1142
- var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, RETRYABLE_HTTP;
1161
+ var RESPONSE_FORMAT_OK, RESPONSE_SCHEMA_OK, JSON_CONTRACT_REMINDER, RESPONSES_ONLY_MODEL_PREFIXES, CHAT_TO_RESPONSES_FIELDS, FOREIGN_ENDPOINT_SUFFIX, TIME_BUDGET_EXHAUSTED, MAX_TIMER_DELAY_MS, RETRYABLE_HTTP;
1143
1162
  var init_portalLlm = __esm({
1144
1163
  "src/lib/memory/portalLlm.ts"() {
1145
1164
  "use strict";
@@ -1159,6 +1178,12 @@ var init_portalLlm = __esm({
1159
1178
  chat: "/responses",
1160
1179
  responses: "/chat/completions"
1161
1180
  };
1181
+ TIME_BUDGET_EXHAUSTED = {
1182
+ kind: "terminal",
1183
+ code: "time-budget-exhausted",
1184
+ reason: "time budget exhausted"
1185
+ };
1186
+ MAX_TIMER_DELAY_MS = 2147483647;
1162
1187
  RETRYABLE_HTTP = /* @__PURE__ */ new Set([408, 409, 425, 429]);
1163
1188
  }
1164
1189
  });
@@ -2520,15 +2545,16 @@ async function refreshEncryptionKeyIfMatches(walletAddress, probeCiphertext, sig
2520
2545
  if (!parsed) {
2521
2546
  return false;
2522
2547
  }
2548
+ const startEpoch = sessionEpoch;
2523
2549
  const cached = refreshCandidatesByAddress.get(walletAddress);
2524
2550
  if (cached) {
2525
- return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, cached);
2551
+ return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, cached, startEpoch);
2526
2552
  }
2527
2553
  let derivePromise = pendingCandidateDerives.get(walletAddress);
2528
2554
  if (!derivePromise) {
2529
2555
  derivePromise = (async () => {
2530
2556
  const candidates2 = await deriveRefreshCandidates(signMessage, embeddedWalletSigner);
2531
- if (candidates2) {
2557
+ if (candidates2 && sessionEpoch === startEpoch) {
2532
2558
  refreshCandidatesByAddress.set(walletAddress, candidates2);
2533
2559
  }
2534
2560
  return candidates2;
@@ -2540,10 +2566,10 @@ async function refreshEncryptionKeyIfMatches(walletAddress, probeCiphertext, sig
2540
2566
  pendingCandidateDerives.set(walletAddress, derivePromise);
2541
2567
  }
2542
2568
  const candidates = await derivePromise;
2543
- if (!candidates) {
2569
+ if (!candidates || sessionEpoch !== startEpoch) {
2544
2570
  return false;
2545
2571
  }
2546
- return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, candidates);
2572
+ return tryCommitCandidatesIfProbeMatches(walletAddress, parsed, candidates, startEpoch);
2547
2573
  }
2548
2574
  function parsePrefixedCiphertext(probeCiphertext) {
2549
2575
  const version = probeCiphertext.startsWith("enc:v3:") ? "v3" : probeCiphertext.startsWith("enc:v2:") ? "v2" : null;
@@ -2586,7 +2612,7 @@ async function deriveRefreshCandidates(signMessage, embeddedWalletSigner) {
2586
2612
  }
2587
2613
  return { legacy: legacyKey, current: currentKey };
2588
2614
  }
2589
- async function tryCommitCandidatesIfProbeMatches(walletAddress, parsed, candidates) {
2615
+ async function tryCommitCandidatesIfProbeMatches(walletAddress, parsed, candidates, startEpoch) {
2590
2616
  const candidateHex = parsed.version === "v2" ? candidates.legacy : candidates.current;
2591
2617
  const keyBytes = hexToBytes(candidateHex);
2592
2618
  const candidateCryptoKey = await crypto.subtle.importKey(
@@ -2604,6 +2630,9 @@ async function tryCommitCandidatesIfProbeMatches(walletAddress, parsed, candidat
2604
2630
  );
2605
2631
  return false;
2606
2632
  }
2633
+ if (sessionEpoch !== startEpoch) {
2634
+ return false;
2635
+ }
2607
2636
  setStoredKey(walletAddress, { legacy: candidates.legacy, current: candidates.current });
2608
2637
  cryptoKeyCache.delete(`${walletAddress}:v2`);
2609
2638
  cryptoKeyCache.delete(`${walletAddress}:v3`);
@@ -14967,6 +14996,16 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
14967
14996
  const probe = await ctx.vaultMemoryCollection.find(id2);
14968
14997
  if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
14969
14998
  if (opts.freeFormOnly && isKinded(probe)) return null;
14999
+ const readStoredContent = probe._getRaw("content");
15000
+ if (opts.expectedContent !== void 0) {
15001
+ const current = await vaultMemoryToStored(
15002
+ probe,
15003
+ ctx.walletAddress,
15004
+ ctx.signMessage,
15005
+ ctx.embeddedWalletSigner
15006
+ );
15007
+ if (current.content !== opts.expectedContent) return null;
15008
+ }
14970
15009
  const levelAfter = (current) => {
14971
15010
  if (opts.level !== void 0) return opts.level;
14972
15011
  if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
@@ -14974,7 +15013,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
14974
15013
  };
14975
15014
  assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
14976
15015
  const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
14977
- const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
15016
+ const encryptedContent = opts.content !== void 0 && ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
14978
15017
  opts.content,
14979
15018
  ctx.walletAddress,
14980
15019
  ctx.signMessage,
@@ -14982,13 +15021,13 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
14982
15021
  ) : opts.content;
14983
15022
  let stale = false;
14984
15023
  const record2 = probe;
14985
- const originalUpdatedAt = record2.updatedAt.getTime();
14986
15024
  await ctx.database.write(async () => {
14987
15025
  await assertCanWrite2(ctx);
14988
- if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
15026
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2) || opts.expectedContent !== void 0 && record2._getRaw("content") !== readStoredContent) {
14989
15027
  stale = true;
14990
15028
  return;
14991
15029
  }
15030
+ const originalUpdatedAt = record2.updatedAt.getTime();
14992
15031
  const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
14993
15032
  const nextLevel = levelAfter(record2);
14994
15033
  assertValidKindLevel(nextKind, nextLevel);
@@ -15004,7 +15043,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
15004
15043
  replayedObservation = opts.observationSourceIds.every((id3) => observedSources.includes(id3));
15005
15044
  }
15006
15045
  await record2.update((r) => {
15007
- r._setRaw("content", encryptedContent);
15046
+ if (encryptedContent !== void 0) r._setRaw("content", encryptedContent);
15008
15047
  if (opts.level !== void 0) {
15009
15048
  r._setRaw("level", nextLevel);
15010
15049
  r._setRaw("scope", scopeForLevel(nextLevel));
@@ -15772,7 +15811,7 @@ function classifyDecay(m, now, policy) {
15772
15811
  if (m.source === "manual" || m.source === SOURCE_PHOTO) return "keep";
15773
15812
  if (isTimeSensitiveType(m.factType) && m.eventTimeEnd !== null) {
15774
15813
  if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
15775
- if (m.eventTimeEnd >= now) return "keep";
15814
+ return "keep";
15776
15815
  }
15777
15816
  if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
15778
15817
  return "keep";
@@ -17284,6 +17323,104 @@ function validate(parsed, originalQuery) {
17284
17323
  return { mode, subQueries };
17285
17324
  }
17286
17325
 
17326
+ // src/lib/memoryVault/vaultPreparation.ts
17327
+ function createVaultPreparation() {
17328
+ return { corpora: /* @__PURE__ */ new WeakMap(), rows: /* @__PURE__ */ new WeakMap() };
17329
+ }
17330
+ var pendingRows = /* @__PURE__ */ new WeakMap();
17331
+ function loadVaultCorpus(ctx, options, preparation) {
17332
+ if (!preparation) return getAllVaultMemoriesOp(ctx, options);
17333
+ const corpusCache = preparation.corpora;
17334
+ let pending = corpusCache.get(ctx);
17335
+ if (!pending) {
17336
+ pending = /* @__PURE__ */ new Map();
17337
+ corpusCache.set(ctx, pending);
17338
+ }
17339
+ const key = JSON.stringify(options ?? {});
17340
+ let request = pending.get(key);
17341
+ if (!request) {
17342
+ const entries = pending;
17343
+ request = getAllVaultMemoriesOp(ctx, options).catch((error) => {
17344
+ entries.delete(key);
17345
+ throw error;
17346
+ });
17347
+ pending.set(key, request);
17348
+ }
17349
+ return request;
17350
+ }
17351
+ function rowRequestsFor(registry2, ctx, maskInput) {
17352
+ let byMask = registry2.get(ctx);
17353
+ if (!byMask) {
17354
+ byMask = /* @__PURE__ */ new Map();
17355
+ registry2.set(ctx, byMask);
17356
+ }
17357
+ let requests = byMask.get(maskInput);
17358
+ if (!requests) {
17359
+ requests = /* @__PURE__ */ new Map();
17360
+ byMask.set(maskInput, requests);
17361
+ }
17362
+ return requests;
17363
+ }
17364
+ function embedVaultRows(ctx, options, rows, preparation) {
17365
+ const pending = rowRequestsFor(pendingRows, ctx, options.maskInput);
17366
+ const prepared = preparation && rowRequestsFor(preparation.rows, ctx, options.maskInput);
17367
+ const model = options.model ?? DEFAULT_API_EMBEDDING_MODEL;
17368
+ const keys = rows.map(
17369
+ (row) => JSON.stringify([
17370
+ row.uniqueId,
17371
+ row.updatedAt?.getTime(),
17372
+ row.content,
17373
+ model,
17374
+ options.baseUrl,
17375
+ options.timeoutMs,
17376
+ options.tokenTimeoutMs,
17377
+ options.totalTimeoutMs
17378
+ ])
17379
+ );
17380
+ const missing = /* @__PURE__ */ new Map();
17381
+ rows.forEach((row, index) => {
17382
+ if (!pending.has(keys[index]) && !prepared?.has(keys[index])) missing.set(keys[index], row);
17383
+ });
17384
+ if (missing.size > 0) {
17385
+ const entries = pending;
17386
+ const batch = Promise.resolve().then(
17387
+ () => generateEmbeddings(
17388
+ [...missing.values()].map((row) => row.content),
17389
+ options
17390
+ )
17391
+ );
17392
+ [...missing].forEach(([key, row], index) => {
17393
+ const request = batch.then((vectors) => {
17394
+ const vector = vectors[index];
17395
+ updateVaultMemoryEmbeddingOp(ctx, row.uniqueId, JSON.stringify(vector), model, {
17396
+ content: row.content,
17397
+ updatedAt: row.updatedAt?.getTime()
17398
+ }).catch(() => {
17399
+ });
17400
+ return vector;
17401
+ }).finally(() => {
17402
+ entries.delete(key);
17403
+ if (entries.size === 0) pendingRows.get(ctx)?.delete(options.maskInput);
17404
+ });
17405
+ pending.set(key, request);
17406
+ });
17407
+ }
17408
+ return Promise.all(
17409
+ keys.map((key) => {
17410
+ const cached = prepared?.get(key);
17411
+ if (cached) return cached;
17412
+ const request = pending.get(key);
17413
+ if (!prepared) return request;
17414
+ const retained = request.catch((error) => {
17415
+ prepared.delete(key);
17416
+ throw error;
17417
+ });
17418
+ prepared.set(key, retained);
17419
+ return retained;
17420
+ })
17421
+ );
17422
+ }
17423
+
17287
17424
  // src/lib/memoryVault/vectorVersion.ts
17288
17425
  var vectorRowVersion = /* @__PURE__ */ new WeakMap();
17289
17426
  function contentFingerprint(content) {
@@ -17846,11 +17983,11 @@ async function rankComposite(originalQuery, originalQueryEmbedding, subQueries,
17846
17983
  return combined.slice(0, limit);
17847
17984
  }
17848
17985
  async function preEmbedVaultMemories(vaultCtx, embeddingOptions, cache, options) {
17849
- const memories = await getAllVaultMemoriesOp(vaultCtx, options);
17986
+ const memories = await loadVaultCorpus(vaultCtx, options);
17850
17987
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
17851
17988
  const uncachedTexts = [];
17852
17989
  const uncachedKeys = [];
17853
- const uncachedIds = [];
17990
+ const uncachedRows = [];
17854
17991
  const uncachedVersions = [];
17855
17992
  for (const m of memories) {
17856
17993
  const content = m.content;
@@ -17869,12 +18006,12 @@ async function preEmbedVaultMemories(vaultCtx, embeddingOptions, cache, options)
17869
18006
  }
17870
18007
  uncachedTexts.push(m.content);
17871
18008
  uncachedKeys.push(m.uniqueId);
17872
- uncachedIds.push(m.uniqueId);
18009
+ uncachedRows.push(m);
17873
18010
  uncachedVersions.push(m.updatedAt);
17874
18011
  }
17875
18012
  }
17876
18013
  if (uncachedTexts.length > 0) {
17877
- const embeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
18014
+ const embeddings = await embedVaultRows(vaultCtx, embeddingOptions, uncachedRows);
17878
18015
  for (let i = 0; i < uncachedKeys.length; i++) {
17879
18016
  cacheRowVector(
17880
18017
  cache,
@@ -17883,13 +18020,6 @@ async function preEmbedVaultMemories(vaultCtx, embeddingOptions, cache, options)
17883
18020
  uncachedVersions[i],
17884
18021
  uncachedTexts[i]
17885
18022
  );
17886
- updateVaultMemoryEmbeddingOp(
17887
- vaultCtx,
17888
- uncachedIds[i],
17889
- JSON.stringify(embeddings[i]),
17890
- currentModel
17891
- ).catch(() => {
17892
- });
17893
18023
  }
17894
18024
  }
17895
18025
  }
@@ -18031,10 +18161,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
18031
18161
  let laneVecs;
18032
18162
  if (opts.embedStats) opts.embedStats.rowsEmbedded += laneRows.length;
18033
18163
  try {
18034
- laneVecs = await generateEmbeddings(
18035
- laneRows.map((m) => m.content),
18036
- embeddingOptions
18037
- );
18164
+ laneVecs = await embedVaultRows(vaultCtx, embeddingOptions, laneRows);
18038
18165
  } catch (err) {
18039
18166
  laneEmbedFailed = true;
18040
18167
  getLogger().warn(
@@ -18048,13 +18175,6 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
18048
18175
  cacheRowVector(cache, m.uniqueId, vec, m.updatedAt, m.content);
18049
18176
  resolvedThisCall.add(m.uniqueId);
18050
18177
  vectored.push({ uniqueId: m.uniqueId, embedding: vec, updatedAt: m.updatedAt });
18051
- updateVaultMemoryEmbeddingOp(
18052
- vaultCtx,
18053
- m.uniqueId,
18054
- JSON.stringify(vecs[i]),
18055
- currentModel
18056
- ).catch(() => {
18057
- });
18058
18178
  });
18059
18179
  }
18060
18180
  }
@@ -18246,9 +18366,10 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
18246
18366
  };
18247
18367
  }
18248
18368
  } else {
18249
- const loaded = await getAllVaultMemoriesOp(
18369
+ const loaded = await loadVaultCorpus(
18250
18370
  vaultCtx,
18251
- Object.keys(queryOpts).length > 0 ? queryOpts : void 0
18371
+ Object.keys(queryOpts).length > 0 ? queryOpts : void 0,
18372
+ searchOptions?.vaultPreparation
18252
18373
  );
18253
18374
  vaultSize = loaded.length;
18254
18375
  rowsDecrypted = loaded.length;
@@ -18321,7 +18442,12 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
18321
18442
  let newEmbeddings;
18322
18443
  embedStats.rowsEmbedded += uncachedTexts.length;
18323
18444
  try {
18324
- newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
18445
+ newEmbeddings = await embedVaultRows(
18446
+ vaultCtx,
18447
+ embeddingOptions,
18448
+ uncachedIndices.map((index) => memories[index]),
18449
+ searchOptions?.vaultPreparation
18450
+ );
18325
18451
  } catch (err) {
18326
18452
  embeddingFailure = true;
18327
18453
  getLogger().warn(
@@ -18337,13 +18463,6 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
18337
18463
  memories[uncachedIndices[j]].updatedAt,
18338
18464
  memories[uncachedIndices[j]].content
18339
18465
  );
18340
- updateVaultMemoryEmbeddingOp(
18341
- vaultCtx,
18342
- memories[uncachedIndices[j]].uniqueId,
18343
- JSON.stringify(newEmbeddings[j]),
18344
- currentModel
18345
- ).catch(() => {
18346
- });
18347
18466
  }
18348
18467
  }
18349
18468
  }
@@ -18748,7 +18867,6 @@ async function retainWithPersistence(content, ctx, options = {}) {
18748
18867
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
18749
18868
  const resurrect = resurrectFields(existing);
18750
18869
  const updated = await ctx.persistence.update(targetId, {
18751
- content: existing.content,
18752
18870
  freeFormOnly: true,
18753
18871
  proofCountIncrement: 1,
18754
18872
  observationSourceIds: options.sourceChunkIds,
@@ -18987,7 +19105,6 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
18987
19105
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
18988
19106
  const resurrect = resurrectFields(existing);
18989
19107
  const updated = await ctx.persistence.update(decision.targetId, {
18990
- content: existing.content,
18991
19108
  freeFormOnly: true,
18992
19109
  proofCountIncrement: 1,
18993
19110
  observationSourceIds: options.sourceChunkIds,
@@ -19015,6 +19132,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19015
19132
  };
19016
19133
  }
19017
19134
  if (decision.action === "update" && decision.targetId && decision.content) {
19135
+ const expectedContent = candidates.find(
19136
+ (candidate) => candidate.id === decision.targetId
19137
+ )?.content;
19138
+ if (expectedContent === void 0) return null;
19018
19139
  const existing = await ctx.persistence.get(decision.targetId);
19019
19140
  if (!existing || existing.supersededBy) {
19020
19141
  return abandonToRace(
@@ -19022,6 +19143,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19022
19143
  `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
19023
19144
  );
19024
19145
  }
19146
+ if (existing.content !== expectedContent) {
19147
+ return abandonToRace(options, `update: target ${decision.targetId} edited before the write`);
19148
+ }
19025
19149
  const mergedSourceIds = unionStrings(
19026
19150
  existing.sourceChunkIds ?? [],
19027
19151
  options.sourceChunkIds ?? []
@@ -19034,6 +19158,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19034
19158
  const resurrect = resurrectFields(existing);
19035
19159
  const updated = await ctx.persistence.update(decision.targetId, {
19036
19160
  content: decision.content,
19161
+ expectedContent,
19037
19162
  freeFormOnly: true,
19038
19163
  proofCountIncrement: 1,
19039
19164
  observationSourceIds: options.sourceChunkIds,
@@ -19046,10 +19171,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19046
19171
  ...factTypeUpdate !== void 0 && { factType: factTypeUpdate }
19047
19172
  });
19048
19173
  if (!updated) {
19049
- await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
19174
+ await assertMergeTargetGoneOrThrow(ctx, decision.targetId, expectedContent);
19050
19175
  return abandonToRace(
19051
19176
  options,
19052
- `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
19177
+ `update: target ${decision.targetId} changed mid-write (consolidated rewrite lost)`
19053
19178
  );
19054
19179
  }
19055
19180
  cacheRowVector(
@@ -19076,9 +19201,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19076
19201
  );
19077
19202
  return null;
19078
19203
  }
19079
- async function assertMergeTargetGoneOrThrow(ctx, targetId) {
19204
+ async function assertMergeTargetGoneOrThrow(ctx, targetId, expectedContent) {
19080
19205
  const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
19081
- if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
19206
+ if (stillExists && (stillExists.kind === null || stillExists.kind === void 0) && (expectedContent === void 0 || stillExists.content === expectedContent)) {
19082
19207
  throw new RetainError(
19083
19208
  "merge-not-persisted",
19084
19209
  `retain: merge into memory ${targetId} failed to persist`
@@ -20898,6 +21023,7 @@ async function recall(query, ctx, options = {}) {
20898
21023
  },
20899
21024
  ...options.rrfK !== void 0 && { rrfK: options.rrfK },
20900
21025
  ...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
21026
+ ...options.vaultPreparation && { vaultPreparation: options.vaultPreparation },
20901
21027
  ...subQueries && { subQueries },
20902
21028
  ...options.scopes && { scopes: options.scopes },
20903
21029
  ...options.folderId !== void 0 && { folderId: options.folderId },
@@ -22489,16 +22615,16 @@ function createRemoteMemoryPipeline(options) {
22489
22615
  create: (input) => write(createRow(input), 0),
22490
22616
  update: async (id2, patch) => {
22491
22617
  const existing = await get(id2);
22492
- if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
22618
+ if (!existing || patch.expectedContent !== void 0 && existing.content !== patch.expectedContent || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
22493
22619
  return null;
22494
22620
  const snapshot = snapshots.get(id2);
22495
22621
  const memory = {
22496
22622
  ...snapshot.memory,
22497
- content: patch.content,
22623
+ content: patch.content ?? snapshot.memory.content,
22498
22624
  updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Math.max(Date.now(), (snapshot.memory.topics_extracted_at ?? 0) + 1)
22499
22625
  };
22500
22626
  if (patch.scope !== void 0) memory.scope = patch.scope;
22501
- if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
22627
+ if (patch.embedding === void 0 && patch.content !== void 0 && patch.content !== snapshot.memory.content) {
22502
22628
  delete memory.embedding;
22503
22629
  delete memory.embedding_model;
22504
22630
  }
@@ -24503,13 +24629,20 @@ async function synthesizeProfile(ctx, options = {}) {
24503
24629
  }
24504
24630
  }
24505
24631
  }
24632
+ const vaultPreparation = createVaultPreparation();
24506
24633
  const settled = await Promise.allSettled(
24507
24634
  facets.map(async (facet) => {
24508
24635
  const prior = previous?.sections.find((s) => s.key === facet.key);
24509
24636
  if (prior && !staleKeys.has(facet.key)) {
24510
24637
  return prior;
24511
24638
  }
24512
- return synthesizeFacet(facet, recallCtx, options, fallbackPriors.get(facet.key));
24639
+ return synthesizeFacet(
24640
+ facet,
24641
+ recallCtx,
24642
+ options,
24643
+ fallbackPriors.get(facet.key),
24644
+ vaultPreparation
24645
+ );
24513
24646
  })
24514
24647
  );
24515
24648
  const sections = settled.map((r, i) => {
@@ -24663,7 +24796,7 @@ async function attributeFacts(ctx, candidates, facets) {
24663
24796
  }
24664
24797
  return keys;
24665
24798
  }
24666
- async function synthesizeFacet(facet, ctx, options, prior) {
24799
+ async function synthesizeFacet(facet, ctx, options, prior, vaultPreparation) {
24667
24800
  const scopes = options.scopes ?? DEFAULT_SCOPES;
24668
24801
  const limit = options.limit ?? DEFAULT_FACET_RECALL_LIMIT;
24669
24802
  const factTypeWeights = { ...DEFAULT_PROFILE_FACT_TYPE_WEIGHTS, ...options.factTypeWeights };
@@ -24680,6 +24813,7 @@ async function synthesizeFacet(facet, ctx, options, prior) {
24680
24813
  };
24681
24814
  }
24682
24815
  const recalled = await recall(facet.query, ctx, {
24816
+ vaultPreparation,
24683
24817
  scopes,
24684
24818
  limit: hasReviewGate ? RECALL_MAX_LIMIT : limit,
24685
24819
  types: ["fact"],