@anuma/sdk 9.1.5 → 9.1.7

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
  });
@@ -5436,7 +5461,7 @@ var mergeHeaders = (...headers) => {
5436
5461
  if (!header || typeof header !== "object") {
5437
5462
  continue;
5438
5463
  }
5439
- const iterator = header instanceof Headers ? headersEntries(header) : Object.entries(header);
5464
+ const iterator = Array.isArray(header) || header instanceof Headers ? headersEntries(new Headers(header)) : Object.entries(header);
5440
5465
  for (const [key, value] of iterator) {
5441
5466
  if (value === null) {
5442
5467
  mergedHeaders.delete(key);
@@ -5712,6 +5737,18 @@ var createClient = (config = {}) => {
5712
5737
  init_clientConfig();
5713
5738
  var client = createClient(createClientConfig(createConfig()));
5714
5739
 
5740
+ // src/clientHeaders.ts
5741
+ function normalizeHeaders(headers) {
5742
+ if (headers instanceof Headers || Array.isArray(headers)) {
5743
+ const normalized = /* @__PURE__ */ Object.create(null);
5744
+ new Headers(headers).forEach((value, name) => {
5745
+ normalized[name] = value;
5746
+ });
5747
+ return normalized;
5748
+ }
5749
+ return headers;
5750
+ }
5751
+
5715
5752
  // src/client/sdk.gen.ts
5716
5753
  var getApiV1CreditsBalance = (options) => (options?.client ?? client).get({ url: "/api/v1/credits/balance", ...options });
5717
5754
  var getApiV1CreditsPacks = (options) => (options?.client ?? client).get({ url: "/api/v1/credits/packs", ...options });
@@ -5720,7 +5757,7 @@ var postApiV1CreditsPurchase = (options) => (options.client ?? client).post({
5720
5757
  ...options,
5721
5758
  headers: {
5722
5759
  "Content-Type": "application/json",
5723
- ...options.headers
5760
+ ...normalizeHeaders(options.headers)
5724
5761
  }
5725
5762
  });
5726
5763
  var postApiV1Embeddings = (options) => (options.client ?? client).post({
@@ -5728,7 +5765,7 @@ var postApiV1Embeddings = (options) => (options.client ?? client).post({
5728
5765
  ...options,
5729
5766
  headers: {
5730
5767
  "Content-Type": "application/json",
5731
- ...options.headers
5768
+ ...normalizeHeaders(options.headers)
5732
5769
  }
5733
5770
  });
5734
5771
  var getApiV1Models = (options) => (options?.client ?? client).get({ url: "/api/v1/models", ...options });
@@ -14971,6 +15008,16 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
14971
15008
  const probe = await ctx.vaultMemoryCollection.find(id2);
14972
15009
  if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
14973
15010
  if (opts.freeFormOnly && isKinded(probe)) return null;
15011
+ const readStoredContent = probe._getRaw("content");
15012
+ if (opts.expectedContent !== void 0) {
15013
+ const current = await vaultMemoryToStored(
15014
+ probe,
15015
+ ctx.walletAddress,
15016
+ ctx.signMessage,
15017
+ ctx.embeddedWalletSigner
15018
+ );
15019
+ if (current.content !== opts.expectedContent) return null;
15020
+ }
14974
15021
  const levelAfter = (current) => {
14975
15022
  if (opts.level !== void 0) return opts.level;
14976
15023
  if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
@@ -14978,7 +15025,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
14978
15025
  };
14979
15026
  assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
14980
15027
  const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
14981
- const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
15028
+ const encryptedContent = opts.content !== void 0 && ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
14982
15029
  opts.content,
14983
15030
  ctx.walletAddress,
14984
15031
  ctx.signMessage,
@@ -14986,13 +15033,13 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
14986
15033
  ) : opts.content;
14987
15034
  let stale = false;
14988
15035
  const record2 = probe;
14989
- const originalUpdatedAt = record2.updatedAt.getTime();
14990
15036
  await ctx.database.write(async () => {
14991
15037
  await assertCanWrite2(ctx);
14992
- if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
15038
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2) || opts.expectedContent !== void 0 && record2._getRaw("content") !== readStoredContent) {
14993
15039
  stale = true;
14994
15040
  return;
14995
15041
  }
15042
+ const originalUpdatedAt = record2.updatedAt.getTime();
14996
15043
  const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
14997
15044
  const nextLevel = levelAfter(record2);
14998
15045
  assertValidKindLevel(nextKind, nextLevel);
@@ -15008,7 +15055,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
15008
15055
  replayedObservation = opts.observationSourceIds.every((id3) => observedSources.includes(id3));
15009
15056
  }
15010
15057
  await record2.update((r) => {
15011
- r._setRaw("content", encryptedContent);
15058
+ if (encryptedContent !== void 0) r._setRaw("content", encryptedContent);
15012
15059
  if (opts.level !== void 0) {
15013
15060
  r._setRaw("level", nextLevel);
15014
15061
  r._setRaw("scope", scopeForLevel(nextLevel));
@@ -15776,7 +15823,7 @@ function classifyDecay(m, now, policy) {
15776
15823
  if (m.source === "manual" || m.source === SOURCE_PHOTO) return "keep";
15777
15824
  if (isTimeSensitiveType(m.factType) && m.eventTimeEnd !== null) {
15778
15825
  if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
15779
- if (m.eventTimeEnd >= now) return "keep";
15826
+ return "keep";
15780
15827
  }
15781
15828
  if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
15782
15829
  return "keep";
@@ -18832,7 +18879,6 @@ async function retainWithPersistence(content, ctx, options = {}) {
18832
18879
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
18833
18880
  const resurrect = resurrectFields(existing);
18834
18881
  const updated = await ctx.persistence.update(targetId, {
18835
- content: existing.content,
18836
18882
  freeFormOnly: true,
18837
18883
  proofCountIncrement: 1,
18838
18884
  observationSourceIds: options.sourceChunkIds,
@@ -19071,7 +19117,6 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19071
19117
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
19072
19118
  const resurrect = resurrectFields(existing);
19073
19119
  const updated = await ctx.persistence.update(decision.targetId, {
19074
- content: existing.content,
19075
19120
  freeFormOnly: true,
19076
19121
  proofCountIncrement: 1,
19077
19122
  observationSourceIds: options.sourceChunkIds,
@@ -19099,6 +19144,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19099
19144
  };
19100
19145
  }
19101
19146
  if (decision.action === "update" && decision.targetId && decision.content) {
19147
+ const expectedContent = candidates.find(
19148
+ (candidate) => candidate.id === decision.targetId
19149
+ )?.content;
19150
+ if (expectedContent === void 0) return null;
19102
19151
  const existing = await ctx.persistence.get(decision.targetId);
19103
19152
  if (!existing || existing.supersededBy) {
19104
19153
  return abandonToRace(
@@ -19106,6 +19155,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19106
19155
  `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
19107
19156
  );
19108
19157
  }
19158
+ if (existing.content !== expectedContent) {
19159
+ return abandonToRace(options, `update: target ${decision.targetId} edited before the write`);
19160
+ }
19109
19161
  const mergedSourceIds = unionStrings(
19110
19162
  existing.sourceChunkIds ?? [],
19111
19163
  options.sourceChunkIds ?? []
@@ -19118,6 +19170,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19118
19170
  const resurrect = resurrectFields(existing);
19119
19171
  const updated = await ctx.persistence.update(decision.targetId, {
19120
19172
  content: decision.content,
19173
+ expectedContent,
19121
19174
  freeFormOnly: true,
19122
19175
  proofCountIncrement: 1,
19123
19176
  observationSourceIds: options.sourceChunkIds,
@@ -19130,10 +19183,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19130
19183
  ...factTypeUpdate !== void 0 && { factType: factTypeUpdate }
19131
19184
  });
19132
19185
  if (!updated) {
19133
- await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
19186
+ await assertMergeTargetGoneOrThrow(ctx, decision.targetId, expectedContent);
19134
19187
  return abandonToRace(
19135
19188
  options,
19136
- `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
19189
+ `update: target ${decision.targetId} changed mid-write (consolidated rewrite lost)`
19137
19190
  );
19138
19191
  }
19139
19192
  cacheRowVector(
@@ -19160,9 +19213,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
19160
19213
  );
19161
19214
  return null;
19162
19215
  }
19163
- async function assertMergeTargetGoneOrThrow(ctx, targetId) {
19216
+ async function assertMergeTargetGoneOrThrow(ctx, targetId, expectedContent) {
19164
19217
  const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
19165
- if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
19218
+ if (stillExists && (stillExists.kind === null || stillExists.kind === void 0) && (expectedContent === void 0 || stillExists.content === expectedContent)) {
19166
19219
  throw new RetainError(
19167
19220
  "merge-not-persisted",
19168
19221
  `retain: merge into memory ${targetId} failed to persist`
@@ -22574,16 +22627,16 @@ function createRemoteMemoryPipeline(options) {
22574
22627
  create: (input) => write(createRow(input), 0),
22575
22628
  update: async (id2, patch) => {
22576
22629
  const existing = await get(id2);
22577
- if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
22630
+ if (!existing || patch.expectedContent !== void 0 && existing.content !== patch.expectedContent || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
22578
22631
  return null;
22579
22632
  const snapshot = snapshots.get(id2);
22580
22633
  const memory = {
22581
22634
  ...snapshot.memory,
22582
- content: patch.content,
22635
+ content: patch.content ?? snapshot.memory.content,
22583
22636
  updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Math.max(Date.now(), (snapshot.memory.topics_extracted_at ?? 0) + 1)
22584
22637
  };
22585
22638
  if (patch.scope !== void 0) memory.scope = patch.scope;
22586
- if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
22639
+ if (patch.embedding === void 0 && patch.content !== void 0 && patch.content !== snapshot.memory.content) {
22587
22640
  delete memory.embedding;
22588
22641
  delete memory.embedding_model;
22589
22642
  }
@@ -5669,7 +5669,8 @@ interface CreateVaultMemoryOptions {
5669
5669
  geohash?: string;
5670
5670
  }
5671
5671
  interface UpdateVaultMemoryOptions {
5672
- content: string;
5672
+ content?: string;
5673
+ expectedContent?: string;
5673
5674
  /** When true, the write is skipped (returns null) if the row carries a profile kind. */
5674
5675
  freeFormOnly?: boolean;
5675
5676
  /**
@@ -6273,9 +6274,10 @@ declare function ttlForType(factType: string | null, policy?: Partial<DecayPolic
6273
6274
  * null `eventTimeEnd` is still ongoing, so this rule does not fire for it.
6274
6275
  * 4. Age fallback — `now - updatedAt > TTL(factType)` → archive. Durable types
6275
6276
  * have Infinity TTL, so this never fires for them; null/unknown use medium.
6276
- * EXCEPTION: a `plan`/`ongoing_context` with a still-upcoming event
6277
- * (`eventTimeEnd >= now`) is kept — it must not age-archive before the event
6278
- * happens; only rule 3 (after it passes) may archive it.
6277
+ * EXCEPTION: a `plan` / `ongoing_context` with an upcoming event or an event
6278
+ * within the grace period (`eventTimeEnd >= now - pastEventGraceMs`) stays
6279
+ * active, even after its activity TTL expires. Rule 3 archives it after the
6280
+ * grace period ends.
6279
6281
  * 5. Otherwise → keep.
6280
6282
  *
6281
6283
  * @param m Plaintext decay inputs for one row.
@@ -6606,7 +6608,9 @@ type MemoryCreate = Pick<CreateVaultMemoryOptions, "content" | "scope" | "factTy
6606
6608
  * `embedding` (with `embeddingModel`) only when you already have the new one.
6607
6609
  * @public
6608
6610
  */
6609
- type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "content" | "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level">;
6611
+ type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level"> & {
6612
+ content: string;
6613
+ };
6610
6614
  /**
6611
6615
  * Fact-only recall. Conversation chunks are message storage, not memory, so
6612
6616
  * the chunk-lane knobs are not part of this surface; nor is `folderId` (see
@@ -5669,7 +5669,8 @@ interface CreateVaultMemoryOptions {
5669
5669
  geohash?: string;
5670
5670
  }
5671
5671
  interface UpdateVaultMemoryOptions {
5672
- content: string;
5672
+ content?: string;
5673
+ expectedContent?: string;
5673
5674
  /** When true, the write is skipped (returns null) if the row carries a profile kind. */
5674
5675
  freeFormOnly?: boolean;
5675
5676
  /**
@@ -6273,9 +6274,10 @@ declare function ttlForType(factType: string | null, policy?: Partial<DecayPolic
6273
6274
  * null `eventTimeEnd` is still ongoing, so this rule does not fire for it.
6274
6275
  * 4. Age fallback — `now - updatedAt > TTL(factType)` → archive. Durable types
6275
6276
  * have Infinity TTL, so this never fires for them; null/unknown use medium.
6276
- * EXCEPTION: a `plan`/`ongoing_context` with a still-upcoming event
6277
- * (`eventTimeEnd >= now`) is kept — it must not age-archive before the event
6278
- * happens; only rule 3 (after it passes) may archive it.
6277
+ * EXCEPTION: a `plan` / `ongoing_context` with an upcoming event or an event
6278
+ * within the grace period (`eventTimeEnd >= now - pastEventGraceMs`) stays
6279
+ * active, even after its activity TTL expires. Rule 3 archives it after the
6280
+ * grace period ends.
6279
6281
  * 5. Otherwise → keep.
6280
6282
  *
6281
6283
  * @param m Plaintext decay inputs for one row.
@@ -6606,7 +6608,9 @@ type MemoryCreate = Pick<CreateVaultMemoryOptions, "content" | "scope" | "factTy
6606
6608
  * `embedding` (with `embeddingModel`) only when you already have the new one.
6607
6609
  * @public
6608
6610
  */
6609
- type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "content" | "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level">;
6611
+ type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level"> & {
6612
+ content: string;
6613
+ };
6610
6614
  /**
6611
6615
  * Fact-only recall. Conversation chunks are message storage, not memory, so
6612
6616
  * the chunk-lane knobs are not part of this surface; nor is `folderId` (see