@anuma/sdk 9.1.5 → 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-7QX4J7KV.mjs";
7
+ } from "./chunk-RSA3S6OA.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
  });
@@ -16788,6 +16813,16 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
16788
16813
  const probe = await ctx.vaultMemoryCollection.find(id2);
16789
16814
  if (probe.isDeleted || probe.supersededBy || !isOwnedByCtxUser(ctx, probe)) return null;
16790
16815
  if (opts.freeFormOnly && isKinded(probe)) return null;
16816
+ const readStoredContent = probe._getRaw("content");
16817
+ if (opts.expectedContent !== void 0) {
16818
+ const current = await vaultMemoryToStored(
16819
+ probe,
16820
+ ctx.walletAddress,
16821
+ ctx.signMessage,
16822
+ ctx.embeddedWalletSigner
16823
+ );
16824
+ if (current.content !== opts.expectedContent) return null;
16825
+ }
16791
16826
  const levelAfter = (current) => {
16792
16827
  if (opts.level !== void 0) return opts.level;
16793
16828
  if (opts.scope === void 0) return resolveMemoryLevel(current.level, current.scope);
@@ -16795,7 +16830,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
16795
16830
  };
16796
16831
  assertValidKindLevel(opts.kind !== void 0 ? opts.kind : probe.kind, levelAfter(probe));
16797
16832
  const encryptedKindValue = await encryptKindValue(ctx, opts.kindValue);
16798
- const encryptedContent = ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
16833
+ const encryptedContent = opts.content !== void 0 && ctx.walletAddress && ctx.signMessage ? await encryptVaultMemoryContent(
16799
16834
  opts.content,
16800
16835
  ctx.walletAddress,
16801
16836
  ctx.signMessage,
@@ -16803,13 +16838,13 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
16803
16838
  ) : opts.content;
16804
16839
  let stale = false;
16805
16840
  const record2 = probe;
16806
- const originalUpdatedAt = record2.updatedAt.getTime();
16807
16841
  await ctx.database.write(async () => {
16808
16842
  await assertCanWrite2(ctx);
16809
- if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2)) {
16843
+ if (record2.isDeleted || record2.supersededBy || !isOwnedByCtxUser(ctx, record2) || opts.freeFormOnly && isKinded(record2) || opts.expectedContent !== void 0 && record2._getRaw("content") !== readStoredContent) {
16810
16844
  stale = true;
16811
16845
  return;
16812
16846
  }
16847
+ const originalUpdatedAt = record2.updatedAt.getTime();
16813
16848
  const nextKind = opts.kind !== void 0 ? opts.kind : record2.kind;
16814
16849
  const nextLevel = levelAfter(record2);
16815
16850
  assertValidKindLevel(nextKind, nextLevel);
@@ -16825,7 +16860,7 @@ async function updateVaultMemoryOp(ctx, id2, opts) {
16825
16860
  replayedObservation = opts.observationSourceIds.every((id3) => observedSources.includes(id3));
16826
16861
  }
16827
16862
  await record2.update((r) => {
16828
- r._setRaw("content", encryptedContent);
16863
+ if (encryptedContent !== void 0) r._setRaw("content", encryptedContent);
16829
16864
  if (opts.level !== void 0) {
16830
16865
  r._setRaw("level", nextLevel);
16831
16866
  r._setRaw("scope", scopeForLevel(nextLevel));
@@ -17593,7 +17628,7 @@ function classifyDecay(m, now, policy) {
17593
17628
  if (m.source === "manual" || m.source === SOURCE_PHOTO) return "keep";
17594
17629
  if (isTimeSensitiveType(m.factType) && m.eventTimeEnd !== null) {
17595
17630
  if (m.eventTimeEnd < now - resolved.pastEventGraceMs) return "archive";
17596
- if (m.eventTimeEnd >= now) return "keep";
17631
+ return "keep";
17597
17632
  }
17598
17633
  if (now - lastActivityAt(m) > ttlForType(m.factType, resolved)) return "archive";
17599
17634
  return "keep";
@@ -21119,7 +21154,6 @@ async function retainWithPersistence(content, ctx, options = {}) {
21119
21154
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
21120
21155
  const resurrect = resurrectFields(existing);
21121
21156
  const updated = await ctx.persistence.update(targetId, {
21122
- content: existing.content,
21123
21157
  freeFormOnly: true,
21124
21158
  proofCountIncrement: 1,
21125
21159
  observationSourceIds: options.sourceChunkIds,
@@ -21358,7 +21392,6 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
21358
21392
  const factTypeUpdate = pickFactTypeUpdate(existing, options.factType);
21359
21393
  const resurrect = resurrectFields(existing);
21360
21394
  const updated = await ctx.persistence.update(decision.targetId, {
21361
- content: existing.content,
21362
21395
  freeFormOnly: true,
21363
21396
  proofCountIncrement: 1,
21364
21397
  observationSourceIds: options.sourceChunkIds,
@@ -21386,6 +21419,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
21386
21419
  };
21387
21420
  }
21388
21421
  if (decision.action === "update" && decision.targetId && decision.content) {
21422
+ const expectedContent = candidates.find(
21423
+ (candidate) => candidate.id === decision.targetId
21424
+ )?.content;
21425
+ if (expectedContent === void 0) return null;
21389
21426
  const existing = await ctx.persistence.get(decision.targetId);
21390
21427
  if (!existing || existing.supersededBy) {
21391
21428
  return abandonToRace(
@@ -21393,6 +21430,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
21393
21430
  `update: target ${decision.targetId} ${existing ? "superseded" : "deleted"} before the write`
21394
21431
  );
21395
21432
  }
21433
+ if (existing.content !== expectedContent) {
21434
+ return abandonToRace(options, `update: target ${decision.targetId} edited before the write`);
21435
+ }
21396
21436
  const mergedSourceIds = unionStrings(
21397
21437
  existing.sourceChunkIds ?? [],
21398
21438
  options.sourceChunkIds ?? []
@@ -21405,6 +21445,7 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
21405
21445
  const resurrect = resurrectFields(existing);
21406
21446
  const updated = await ctx.persistence.update(decision.targetId, {
21407
21447
  content: decision.content,
21448
+ expectedContent,
21408
21449
  freeFormOnly: true,
21409
21450
  proofCountIncrement: 1,
21410
21451
  observationSourceIds: options.sourceChunkIds,
@@ -21417,10 +21458,10 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
21417
21458
  ...factTypeUpdate !== void 0 && { factType: factTypeUpdate }
21418
21459
  });
21419
21460
  if (!updated) {
21420
- await assertMergeTargetGoneOrThrow(ctx, decision.targetId);
21461
+ await assertMergeTargetGoneOrThrow(ctx, decision.targetId, expectedContent);
21421
21462
  return abandonToRace(
21422
21463
  options,
21423
- `update: target ${decision.targetId} deleted mid-write (consolidated rewrite lost)`
21464
+ `update: target ${decision.targetId} changed mid-write (consolidated rewrite lost)`
21424
21465
  );
21425
21466
  }
21426
21467
  cacheRowVector(
@@ -21447,9 +21488,9 @@ async function tryConsolidate(trimmed, ctx, options, prepared) {
21447
21488
  );
21448
21489
  return null;
21449
21490
  }
21450
- async function assertMergeTargetGoneOrThrow(ctx, targetId) {
21491
+ async function assertMergeTargetGoneOrThrow(ctx, targetId, expectedContent) {
21451
21492
  const stillExists = await (ctx.persistence.getFresh ? ctx.persistence.getFresh(targetId) : ctx.persistence.get(targetId));
21452
- if (stillExists && (stillExists.kind === null || stillExists.kind === void 0)) {
21493
+ if (stillExists && (stillExists.kind === null || stillExists.kind === void 0) && (expectedContent === void 0 || stillExists.content === expectedContent)) {
21453
21494
  throw new RetainError(
21454
21495
  "merge-not-persisted",
21455
21496
  `retain: merge into memory ${targetId} failed to persist`
@@ -24887,16 +24928,16 @@ function createRemoteMemoryPipeline(options) {
24887
24928
  create: (input) => write(createRow(input), 0),
24888
24929
  update: async (id2, patch) => {
24889
24930
  const existing = await get(id2);
24890
- if (!existing || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
24931
+ if (!existing || patch.expectedContent !== void 0 && existing.content !== patch.expectedContent || patch.freeFormOnly && existing.kind !== null && existing.kind !== void 0)
24891
24932
  return null;
24892
24933
  const snapshot = snapshots.get(id2);
24893
24934
  const memory = {
24894
24935
  ...snapshot.memory,
24895
- content: patch.content,
24936
+ content: patch.content ?? snapshot.memory.content,
24896
24937
  updated_at: patch.preserveUpdatedAt ? snapshot.memory.updated_at : Math.max(Date.now(), (snapshot.memory.topics_extracted_at ?? 0) + 1)
24897
24938
  };
24898
24939
  if (patch.scope !== void 0) memory.scope = patch.scope;
24899
- if (patch.embedding === void 0 && patch.content !== snapshot.memory.content) {
24940
+ if (patch.embedding === void 0 && patch.content !== void 0 && patch.content !== snapshot.memory.content) {
24900
24941
  delete memory.embedding;
24901
24942
  delete memory.embedding_model;
24902
24943
  }
@@ -38650,17 +38691,24 @@ var import_react20 = require("react");
38650
38691
  init_clientConfig();
38651
38692
  function useTools(options) {
38652
38693
  const { getToken, baseUrl = BASE_URL, includeTools, autoFetch = true } = options;
38653
- const [tools, setTools] = (0, import_react20.useState)([]);
38694
+ const [allTools, setAllTools] = (0, import_react20.useState)([]);
38654
38695
  const [checksum, setChecksum] = (0, import_react20.useState)(getToolsChecksum2);
38655
38696
  const [isLoading, setIsLoading] = (0, import_react20.useState)(false);
38656
38697
  const [error, setError] = (0, import_react20.useState)(null);
38698
+ const includeToolsRef = (0, import_react20.useRef)(includeTools);
38699
+ if (includeTools !== includeToolsRef.current && (includeTools === void 0 || includeToolsRef.current === void 0 || includeTools.length !== includeToolsRef.current.length || includeTools.some((name, i) => name !== includeToolsRef.current?.[i]))) {
38700
+ includeToolsRef.current = includeTools;
38701
+ }
38702
+ const stableIncludeTools = includeToolsRef.current;
38703
+ const tools = (0, import_react20.useMemo)(
38704
+ () => filterServerTools(allTools, stableIncludeTools),
38705
+ [allTools, stableIncludeTools]
38706
+ );
38657
38707
  const getTokenRef = (0, import_react20.useRef)(getToken);
38658
38708
  const baseUrlRef = (0, import_react20.useRef)(baseUrl);
38659
- const includeToolsRef = (0, import_react20.useRef)(includeTools);
38660
38709
  (0, import_react20.useEffect)(() => {
38661
38710
  getTokenRef.current = getToken;
38662
38711
  baseUrlRef.current = baseUrl;
38663
- includeToolsRef.current = includeTools;
38664
38712
  });
38665
38713
  const fetchTools = (0, import_react20.useCallback)(async (forceRefresh = false) => {
38666
38714
  setIsLoading(true);
@@ -38671,8 +38719,7 @@ function useTools(options) {
38671
38719
  baseUrl: baseUrlRef.current,
38672
38720
  forceRefresh
38673
38721
  });
38674
- const filteredTools = filterServerTools(fetchedTools, includeToolsRef.current);
38675
- setTools(filteredTools);
38722
+ setAllTools(fetchedTools);
38676
38723
  setChecksum(getToolsChecksum2());
38677
38724
  } catch (err) {
38678
38725
  setError(err instanceof Error ? err : new Error(String(err)));
@@ -38696,11 +38743,6 @@ function useTools(options) {
38696
38743
  },
38697
38744
  [refresh]
38698
38745
  );
38699
- (0, import_react20.useEffect)(() => {
38700
- if (tools.length > 0 && includeTools !== void 0) {
38701
- setTools((currentTools) => filterServerTools(currentTools, includeTools));
38702
- }
38703
- }, [includeTools, tools.length]);
38704
38746
  const hasFetchedRef = (0, import_react20.useRef)(false);
38705
38747
  (0, import_react20.useEffect)(() => {
38706
38748
  if (autoFetch && !hasFetchedRef.current) {
@@ -6185,7 +6185,8 @@ interface CreateVaultMemoryOptions {
6185
6185
  geohash?: string;
6186
6186
  }
6187
6187
  interface UpdateVaultMemoryOptions {
6188
- content: string;
6188
+ content?: string;
6189
+ expectedContent?: string;
6189
6190
  /** When true, the write is skipped (returns null) if the row carries a profile kind. */
6190
6191
  freeFormOnly?: boolean;
6191
6192
  /**
@@ -6878,9 +6879,10 @@ declare function ttlForType(factType: string | null, policy?: Partial<DecayPolic
6878
6879
  * null `eventTimeEnd` is still ongoing, so this rule does not fire for it.
6879
6880
  * 4. Age fallback — `now - updatedAt > TTL(factType)` → archive. Durable types
6880
6881
  * have Infinity TTL, so this never fires for them; null/unknown use medium.
6881
- * EXCEPTION: a `plan`/`ongoing_context` with a still-upcoming event
6882
- * (`eventTimeEnd >= now`) is kept — it must not age-archive before the event
6883
- * happens; only rule 3 (after it passes) may archive it.
6882
+ * EXCEPTION: a `plan` / `ongoing_context` with an upcoming event or an event
6883
+ * within the grace period (`eventTimeEnd >= now - pastEventGraceMs`) stays
6884
+ * active, even after its activity TTL expires. Rule 3 archives it after the
6885
+ * grace period ends.
6884
6886
  * 5. Otherwise → keep.
6885
6887
  *
6886
6888
  * @param m Plaintext decay inputs for one row.
@@ -7211,7 +7213,9 @@ type MemoryCreate = Pick<CreateVaultMemoryOptions, "content" | "scope" | "factTy
7211
7213
  * `embedding` (with `embeddingModel`) only when you already have the new one.
7212
7214
  * @public
7213
7215
  */
7214
- type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "content" | "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level">;
7216
+ type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level"> & {
7217
+ content: string;
7218
+ };
7215
7219
  /**
7216
7220
  * Fact-only recall. Conversation chunks are message storage, not memory, so
7217
7221
  * the chunk-lane knobs are not part of this surface; nor is `folderId` (see
@@ -6185,7 +6185,8 @@ interface CreateVaultMemoryOptions {
6185
6185
  geohash?: string;
6186
6186
  }
6187
6187
  interface UpdateVaultMemoryOptions {
6188
- content: string;
6188
+ content?: string;
6189
+ expectedContent?: string;
6189
6190
  /** When true, the write is skipped (returns null) if the row carries a profile kind. */
6190
6191
  freeFormOnly?: boolean;
6191
6192
  /**
@@ -6878,9 +6879,10 @@ declare function ttlForType(factType: string | null, policy?: Partial<DecayPolic
6878
6879
  * null `eventTimeEnd` is still ongoing, so this rule does not fire for it.
6879
6880
  * 4. Age fallback — `now - updatedAt > TTL(factType)` → archive. Durable types
6880
6881
  * have Infinity TTL, so this never fires for them; null/unknown use medium.
6881
- * EXCEPTION: a `plan`/`ongoing_context` with a still-upcoming event
6882
- * (`eventTimeEnd >= now`) is kept — it must not age-archive before the event
6883
- * happens; only rule 3 (after it passes) may archive it.
6882
+ * EXCEPTION: a `plan` / `ongoing_context` with an upcoming event or an event
6883
+ * within the grace period (`eventTimeEnd >= now - pastEventGraceMs`) stays
6884
+ * active, even after its activity TTL expires. Rule 3 archives it after the
6885
+ * grace period ends.
6884
6886
  * 5. Otherwise → keep.
6885
6887
  *
6886
6888
  * @param m Plaintext decay inputs for one row.
@@ -7211,7 +7213,9 @@ type MemoryCreate = Pick<CreateVaultMemoryOptions, "content" | "scope" | "factTy
7211
7213
  * `embedding` (with `embeddingModel`) only when you already have the new one.
7212
7214
  * @public
7213
7215
  */
7214
- type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "content" | "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level">;
7216
+ type MemoryUpdate = Pick<UpdateVaultMemoryOptions, "scope" | "factType" | "eventTime" | "embedding" | "embeddingModel" | "kind" | "kindValue" | "level"> & {
7217
+ content: string;
7218
+ };
7215
7219
  /**
7216
7220
  * Fact-only recall. Conversation chunks are message storage, not memory, so
7217
7221
  * the chunk-lane knobs are not part of this surface; nor is `folderId` (see