@anuma/sdk 6.38.0 → 6.39.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.
@@ -4296,15 +4296,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
4296
4296
 
4297
4297
  Once the user HAS given an explicit build instruction, you are in App Builder mode: you produce polished, production-quality React apps that feel designed \u2014 not generic.
4298
4298
 
4299
- DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a logic, data, or behavior-only change, skip the brief and just make the change.
4299
+ DESIGN: on the initial build, before writing code, briefly state (2-3 sentences) what you want this app to feel like \u2014 name the specific fonts, the palette in hex, and one signature detail. Be concrete: "Fraunces display + Inter body + JetBrains Mono metadata, terracotta #b75432 accent on bone #f3efe6, paper-grain texture via inline SVG noise" is the kind of specificity that anchors the build. Default to nothing: don't pick "safe modern productivity" unless the brief literally asks for utilitarian. On later turns, state a design brief only when the change is visual (a restyle, new theme, or new UI); for a text, logic, data, or behavior-only change, skip the brief and just make the change.
4300
+
4301
+ EDIT SCOPE: Change only the files and lines required by the current user request. A title rename is a text edit, not a design change. Preserve styles, dependencies, and unrelated logic on text edits. Design feedback does not authorize unrelated edits.
4300
4302
 
4301
4303
  WORKFLOW:
4302
4304
  1. NEVER output code as text or markdown. ALWAYS use tools.
4303
4305
  2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
4304
4306
  3. patch_file requires read_file for that path earlier in the conversation (or create_file in the same conversation, which counts). read_file output is numbered "42: <text>" \u2014 the prefix is display-only; never copy it into "find". Each "find" must match exactly one location \u2014 include 2-3 lines of surrounding context. Pass multiple patches per call to change distinct locations.
4305
4307
  4. Prefer patch_file for changes to existing files \u2014 surgical, reviewable, preserves surrounding code. Reserve create_file overwrites for substantial restructuring. Inserts: find the line before, replace with that line + the new line. Deletes: empty replace.
4306
- 5. After substantial changes, call critique_design first (taste, hierarchy, distinctiveness, weakest decision) and then audit_design (mechanical: tokens, focus states, aria-labels, alt, heading order). Patch what each surfaces. critique catches taste issues no checklist would; audit catches mechanics you'd miss. Run both; act on both.
4307
- 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip \u2014 audit + critique are your feedback in that case.
4308
+ 5. On the initial build, when adding new UI, or after user-requested design changes, call critique_design first and then audit_design. Critique checks taste, hierarchy, and distinctiveness. Audit checks tokens, focus states, aria-labels, alt text, and heading order. Patch only issues within the current user request. For text, logic, or data edits, skip both design tools.
4309
+ 6. Before declaring done, call verify_app. The host's preview runtime reports whether your app actually mounted and surfaces any errors it captured \u2014 hallucinated imports, syntax the bundler rejected, undefined components, runtime crashes. If \`rendered\` is false or \`errors\` is non-empty, fix every error before the next message. If the response includes a \`note\` that verify_app isn't wired in this host, skip runtime verification. An unavailable runtime verifier does not authorize design changes. Use audit_design and critique_design only for the initial build, adding new UI, or user-requested design changes.
4308
4310
  7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
4309
4311
 
4310
4312
  STRUCTURE:
@@ -4470,12 +4472,13 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
4470
4472
  if (!cache) return true;
4471
4473
  return Date.now() - cache.timestamp > expirationMs;
4472
4474
  }
4473
- function buildCacheEntry(tools, checksum) {
4475
+ function buildCacheEntry(tools, checksum, etag) {
4474
4476
  return {
4475
4477
  tools,
4476
4478
  timestamp: Date.now(),
4477
4479
  version: CACHE_VERSION,
4478
- ...checksum && { checksum }
4480
+ ...checksum && { checksum },
4481
+ ...etag && { etag }
4479
4482
  };
4480
4483
  }
4481
4484
  function writeLocalStorageCache(entry) {
@@ -4510,19 +4513,36 @@ function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
4510
4513
  const cachedChecksum = getToolsChecksum2(cache);
4511
4514
  return cachedChecksum instanceof Promise ? cachedChecksum.then(decide) : decide(cachedChecksum);
4512
4515
  }
4513
- async function fetchServerToolsFromApi(baseUrl, token) {
4514
- const response = await fetch(`${baseUrl}/api/v1/tools`, {
4516
+ async function fetchServerToolsFromApi(baseUrl, authHeaders, etag) {
4517
+ const request = (validator) => fetch(`${baseUrl}/api/v1/tools`, {
4515
4518
  method: "GET",
4516
4519
  headers: {
4517
- Authorization: `Bearer ${token}`,
4518
- "Content-Type": "application/json"
4520
+ ...authHeaders,
4521
+ "Content-Type": "application/json",
4522
+ ...validator && { "If-None-Match": validator }
4519
4523
  }
4520
4524
  });
4525
+ let response;
4526
+ try {
4527
+ response = await request(etag);
4528
+ } catch (error) {
4529
+ if (!etag || !(error instanceof TypeError)) throw error;
4530
+ etag = void 0;
4531
+ response = await request();
4532
+ }
4533
+ if (etag && response.status === 304) {
4534
+ return { notModified: true };
4535
+ }
4521
4536
  if (!response.ok) {
4522
4537
  throw new Error(`Failed to fetch server tools: ${response.status}`);
4523
4538
  }
4524
4539
  const data = await response.json();
4525
- return convertServerToolsResponse(data);
4540
+ const responseEtag = response.headers?.get("ETag") ?? void 0;
4541
+ return {
4542
+ notModified: false,
4543
+ ...convertServerToolsResponse(data),
4544
+ ...responseEtag && { etag: responseEtag }
4545
+ };
4526
4546
  }
4527
4547
  async function getServerTools(options) {
4528
4548
  const {
@@ -4554,34 +4574,30 @@ async function getServerTools(options) {
4554
4574
  try {
4555
4575
  const { BASE_URL: BASE_URL2 } = await import("./clientConfig-VPOGQRNP.mjs");
4556
4576
  const effectiveBaseUrl = baseUrl ?? BASE_URL2;
4577
+ const validator = cached && !forceRefresh ? cached.etag : void 0;
4578
+ let authHeaders;
4557
4579
  if (apiKey) {
4558
- const response = await fetch(`${effectiveBaseUrl}/api/v1/tools`, {
4559
- method: "GET",
4560
- headers: {
4561
- "X-API-Key": apiKey,
4562
- "Content-Type": "application/json"
4563
- }
4564
- });
4565
- if (!response.ok) {
4566
- throw new Error(`Failed to fetch server tools: ${response.status}`);
4580
+ authHeaders = { "X-API-Key": apiKey };
4581
+ } else {
4582
+ if (!getToken) {
4583
+ getLogger().warn("[serverTools] No auth method available for fetching tools");
4584
+ return cached?.tools ?? [];
4567
4585
  }
4568
- const data = await response.json();
4569
- const { tools: tools2, checksum: checksum2 } = convertServerToolsResponse(data);
4570
- await persistCache(buildCacheEntry(tools2, checksum2));
4571
- return tools2;
4572
- }
4573
- if (!getToken) {
4574
- getLogger().warn("[serverTools] No auth method available for fetching tools");
4575
- return cached?.tools ?? [];
4586
+ const token = await getToken();
4587
+ if (!token) {
4588
+ getLogger().warn("[serverTools] No auth token available for fetching tools");
4589
+ return cached?.tools ?? [];
4590
+ }
4591
+ authHeaders = { Authorization: `Bearer ${token}` };
4576
4592
  }
4577
- const token = await getToken();
4578
- if (!token) {
4579
- getLogger().warn("[serverTools] No auth token available for fetching tools");
4580
- return cached?.tools ?? [];
4593
+ const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
4594
+ if (result.notModified) {
4595
+ const confirmed = cached;
4596
+ await persistCache({ ...confirmed, timestamp: Date.now() });
4597
+ return confirmed.tools;
4581
4598
  }
4582
- const { tools, checksum } = await fetchServerToolsFromApi(effectiveBaseUrl, token);
4583
- await persistCache(buildCacheEntry(tools, checksum));
4584
- return tools;
4599
+ await persistCache(buildCacheEntry(result.tools, result.checksum, result.etag));
4600
+ return result.tools;
4585
4601
  } catch (error) {
4586
4602
  getLogger().error("[serverTools] Failed to fetch server tools:", error);
4587
4603
  if (cached?.tools) {
@@ -17084,7 +17100,6 @@ async function recall(query, ctx, options = {}) {
17084
17100
  }
17085
17101
  const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
17086
17102
  const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
17087
- const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
17088
17103
  const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
17089
17104
  const prepStart = nowMs2();
17090
17105
  let sharedEmbedMs = 0;
@@ -17113,13 +17128,12 @@ async function recall(query, ctx, options = {}) {
17113
17128
  safeLane(
17114
17129
  "graph",
17115
17130
  () => graphLaneFailed = true,
17116
- () => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
17117
- ...options.maxHops !== void 0 && { maxHops: options.maxHops },
17118
- ...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
17119
- ...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
17120
- ...options.rrfK !== void 0 && { rrfK: options.rrfK },
17121
- ...graphRefiner && { refineNeighbors: graphRefiner }
17122
- })
17131
+ () => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(
17132
+ query,
17133
+ ctx,
17134
+ flags.traverse,
17135
+ graphTraversalOptions(options, flags.traverse)
17136
+ )
17123
17137
  ),
17124
17138
  wantsTemporal ? safeLane(
17125
17139
  "temporal",
@@ -17338,6 +17352,16 @@ function toFactMemory(r, now) {
17338
17352
  updatedAt: r.updatedAt ?? /* @__PURE__ */ new Date(0)
17339
17353
  };
17340
17354
  }
17355
+ function graphTraversalOptions(options, traverse) {
17356
+ const refineNeighbors = traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
17357
+ return {
17358
+ ...options.maxHops !== void 0 && { maxHops: options.maxHops },
17359
+ ...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
17360
+ ...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
17361
+ ...options.rrfK !== void 0 && { rrfK: options.rrfK },
17362
+ ...refineNeighbors && { refineNeighbors }
17363
+ };
17364
+ }
17341
17365
  async function buildGraphLaneRanking(query, ctx, traverse = false, traversalOptions = {}) {
17342
17366
  const entityCtx = ctx.entityCtx ?? ctx.vaultCtx?.entityCtx;
17343
17367
  if (!entityCtx) return [];
@@ -17503,24 +17527,33 @@ function isDumpQuery(query) {
17503
17527
  return false;
17504
17528
  }
17505
17529
  async function listRecentFacts(ctx, limit, toolOptions) {
17530
+ const store = toolOptions?.memoryStore;
17506
17531
  const vaultCtx = ctx.vaultCtx;
17507
- if (!vaultCtx) return [];
17508
- const ordered = await getVaultRankingProjectionsOp(vaultCtx, {
17532
+ if (!vaultCtx && !store) return [];
17533
+ const read = (ids) => store ? store.list({ memoryIds: ids }) : getVaultMemoriesByIdsOp(vaultCtx, ids);
17534
+ const filters = {
17509
17535
  ...toolOptions?.scopes && { scopes: toolOptions.scopes },
17510
- ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
17536
+ ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds }
17537
+ };
17538
+ const project = (size) => store ? store.listProjections({ ...filters, limit: size }) : getVaultRankingProjectionsOp(vaultCtx, {
17539
+ ...filters,
17511
17540
  ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId }
17512
17541
  });
17513
17542
  const readable = [];
17514
- for (let i = 0; i < ordered.length && readable.length < limit; i += limit) {
17515
- const batch = ordered.slice(i, i + limit).map((p) => p.uniqueId);
17516
- const byId = new Map(
17517
- (await getVaultMemoriesByIdsOp(vaultCtx, batch)).map((m) => [m.uniqueId, m])
17518
- );
17519
- for (const id of batch) {
17520
- const m = byId.get(id);
17521
- if (m && !isEncrypted(m.content)) readable.push(m);
17522
- if (readable.length >= limit) break;
17543
+ let start = 0;
17544
+ for (let size = limit; readable.length < limit; size *= 2) {
17545
+ const ordered = await project(size);
17546
+ for (let i = start; i < ordered.length && readable.length < limit; i += limit) {
17547
+ const batch = ordered.slice(i, i + limit).map((p) => p.uniqueId);
17548
+ const byId = new Map((await read(batch)).map((m) => [m.uniqueId, m]));
17549
+ for (const id of batch) {
17550
+ const m = byId.get(id);
17551
+ if (m && !isEncrypted(m.content)) readable.push(m);
17552
+ if (readable.length >= limit) break;
17553
+ }
17523
17554
  }
17555
+ if (!store || ordered.length < size) break;
17556
+ start = ordered.length;
17524
17557
  }
17525
17558
  return readable.map((m) => ({
17526
17559
  id: m.uniqueId,
@@ -17537,6 +17570,8 @@ async function listRecentFacts(ctx, limit, toolOptions) {
17537
17570
  }));
17538
17571
  }
17539
17572
  function createRecallTool(ctx, toolOptions, callbacks) {
17573
+ if (toolOptions?.memoryStore && toolOptions.folderId !== void 0)
17574
+ throw new Error("Folders are not supported with a memoryStore");
17540
17575
  const defaultTypes = toolOptions?.types ?? ["fact", "chunk"];
17541
17576
  const defaultLimit = toolOptions?.limit ?? DEFAULT_LIMIT2;
17542
17577
  const defaultBudget = toolOptions?.budget ?? DEFAULT_BUDGET2;
@@ -17608,7 +17643,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
17608
17643
  let surfaced = 0;
17609
17644
  try {
17610
17645
  let recallDegraded = [];
17611
- const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && ctx.vaultCtx !== void 0;
17646
+ const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && (ctx.vaultCtx !== void 0 || toolOptions?.memoryStore !== void 0);
17612
17647
  let result;
17613
17648
  if (wantsRecent) {
17614
17649
  result = { memories: await listRecentFacts(ctx, effectiveLimit, toolOptions) };
@@ -18110,6 +18145,7 @@ function createLocalMemoryStore(options) {
18110
18145
  });
18111
18146
  };
18112
18147
  return {
18148
+ masksEmbeddingInput: options.embeddingOptions.maskInput !== void 0,
18113
18149
  list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
18114
18150
  get: (id) => getVaultMemoryOp(vaultCtx, id),
18115
18151
  listArchived: async () => {
@@ -18191,6 +18227,22 @@ function createLocalMemoryStore(options) {
18191
18227
  { vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
18192
18228
  retainOptions
18193
18229
  ),
18230
+ factSource: {
18231
+ search: (query, searchOptions) => searchVaultMemoriesWithSize(
18232
+ query,
18233
+ vaultCtx,
18234
+ options.embeddingOptions,
18235
+ vaultCache,
18236
+ searchOptions
18237
+ ),
18238
+ graphRanking: (query, traverse, recallOptions) => buildGraphLaneRanking(
18239
+ query,
18240
+ { vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions },
18241
+ traverse,
18242
+ graphTraversalOptions(recallOptions, traverse)
18243
+ ),
18244
+ temporalRanking: (query, now) => buildTemporalLaneRanking(query, vaultCtx, now)
18245
+ },
18194
18246
  subscribe: (onChange, subscribeOptions) => {
18195
18247
  const afterFirst = () => {
18196
18248
  let first = true;
@@ -19077,38 +19129,31 @@ function createRemoteMemoryPipeline(options) {
19077
19129
  };
19078
19130
  return { prepare, port };
19079
19131
  };
19080
- return {
19081
- recall: async (query, recallOptions = {}) => {
19132
+ const factSource = {
19133
+ graphRanking: options.graphRanking,
19134
+ temporalRanking: options.temporalRanking,
19135
+ search: async (text13, searchOptions) => {
19082
19136
  const { prepare } = operation("recall");
19083
- return recall(
19084
- query,
19085
- {
19086
- embeddingOptions,
19087
- factSource: {
19088
- graphRanking: options.graphRanking,
19089
- temporalRanking: options.temporalRanking,
19090
- search: async (text13, searchOptions) => {
19091
- const prepared = await prepare(text13, searchOptions);
19092
- const ranked = await rankPreparedVaultCandidates(
19093
- text13,
19094
- prepared,
19095
- embeddingOptions,
19096
- searchOptions
19097
- );
19098
- return {
19099
- ...ranked,
19100
- rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
19101
- decryptLast: true,
19102
- rowsDecrypted: prepared.rowsDecrypted,
19103
- queryEmbedMs: prepared.queryEmbedMs,
19104
- rowsEmbedded: 0
19105
- };
19106
- }
19107
- }
19108
- },
19109
- { ...recallOptions, types: ["fact"] }
19137
+ const prepared = await prepare(text13, searchOptions);
19138
+ const ranked = await rankPreparedVaultCandidates(
19139
+ text13,
19140
+ prepared,
19141
+ embeddingOptions,
19142
+ searchOptions
19110
19143
  );
19111
- },
19144
+ return {
19145
+ ...ranked,
19146
+ rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
19147
+ decryptLast: true,
19148
+ rowsDecrypted: prepared.rowsDecrypted,
19149
+ queryEmbedMs: prepared.queryEmbedMs,
19150
+ rowsEmbedded: 0
19151
+ };
19152
+ }
19153
+ };
19154
+ return {
19155
+ factSource,
19156
+ recall: async (query, recallOptions = {}) => recall(query, { embeddingOptions, factSource }, { ...recallOptions, types: ["fact"] }),
19112
19157
  retain: async (content, retainOptions) => {
19113
19158
  const { port } = operation("retain");
19114
19159
  return retainWithPersistence(
@@ -19469,6 +19514,7 @@ function createRemoteMemoryStore(options) {
19469
19514
  });
19470
19515
  };
19471
19516
  return {
19517
+ masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
19472
19518
  list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
19473
19519
  (r) => stored(r.memory)
19474
19520
  ),
@@ -19664,6 +19710,7 @@ function createRemoteMemoryStore(options) {
19664
19710
  })
19665
19711
  ),
19666
19712
  recall: (query, recallOptions) => pipeline.recall(query, recallOptions),
19713
+ factSource: pipeline.factSource,
19667
19714
  retain: async (content, retainOptions) => {
19668
19715
  const result = await pipeline.retain(content, retainOptions);
19669
19716
  if (result.action === "create" || result.action === "supersede") notify("membership");
@@ -21427,19 +21474,20 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
21427
21474
  const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
21428
21475
  const folderId = searchOptions?.folderId ?? argFolderId;
21429
21476
  if (searchOptions?.useFusion === false) {
21430
- const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
21477
+ const legacyOptions = {
21478
+ limit: requestLimit,
21479
+ minSimilarity,
21480
+ useFusion: false,
21481
+ ...tuningForward,
21482
+ ...folderId !== void 0 && { folderId },
21483
+ ...searchOptions?.scopes && { scopes: searchOptions.scopes }
21484
+ };
21485
+ const { results: legacy, embeddingsUnavailable } = "retain" in vaultCtx ? await vaultCtx.factSource.search(query, legacyOptions) : await searchVaultMemoriesWithSize(
21431
21486
  query,
21432
21487
  vaultCtx,
21433
21488
  embeddingOptions,
21434
21489
  cache,
21435
- {
21436
- limit: requestLimit,
21437
- minSimilarity,
21438
- useFusion: false,
21439
- ...tuningForward,
21440
- ...folderId !== void 0 && { folderId },
21441
- ...searchOptions?.scopes && { scopes: searchOptions.scopes }
21442
- }
21490
+ legacyOptions
21443
21491
  );
21444
21492
  if (legacy.length === 0) {
21445
21493
  return embeddingsUnavailable ? EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL : "No relevant memories found in the vault.";
@@ -21458,7 +21506,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
21458
21506
  let recallDegraded = [];
21459
21507
  const result = await recall(
21460
21508
  query,
21461
- { vaultCtx, embeddingOptions, vaultCache: cache },
21509
+ "retain" in vaultCtx ? { factSource: vaultCtx.factSource, embeddingOptions } : { vaultCtx, embeddingOptions, vaultCache: cache },
21462
21510
  {
21463
21511
  onDiagnostics: (d) => {
21464
21512
  recallDegraded = d.degraded;
@@ -21538,8 +21586,10 @@ function describeWriteOutcome(outcome2) {
21538
21586
  }
21539
21587
  }
21540
21588
  function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
21589
+ const store = "retain" in vaultCtx ? vaultCtx : void 0;
21590
+ const ctx = "retain" in vaultCtx ? void 0 : vaultCtx;
21541
21591
  const hasOnSave = !!options?.onSave;
21542
- const folderNames = options?.folderMap ? Array.from(options.folderMap.keys()) : [];
21592
+ const folderNames = !store && options?.folderMap ? Array.from(options.folderMap.keys()) : [];
21543
21593
  return {
21544
21594
  type: "function",
21545
21595
  function: {
@@ -21584,7 +21634,7 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
21584
21634
  let previousContent;
21585
21635
  const scope = options?.scope ?? "private";
21586
21636
  if (isUpdate) {
21587
- const existing = await getVaultMemoryOp(vaultCtx, id);
21637
+ const existing = store ? await store.get(id) : await getVaultMemoryOp(ctx, id);
21588
21638
  if (!existing) {
21589
21639
  return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
21590
21640
  }
@@ -21605,9 +21655,18 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
21605
21655
  return isUpdate ? `Memory update was cancelled by the user. The memory "${id}" was not modified.` : "Memory save was cancelled by the user. No memory was created.";
21606
21656
  }
21607
21657
  }
21608
- if (isUpdate) {
21658
+ if (isUpdate && store) {
21659
+ const updated = await store.update(id, {
21660
+ content,
21661
+ ...factType !== void 0 && { factType }
21662
+ });
21663
+ if (!updated) {
21664
+ return `Error: Failed to update memory "${id}".`;
21665
+ }
21666
+ return `Memory updated successfully (ID: ${updated.uniqueId}).`;
21667
+ } else if (isUpdate) {
21609
21668
  const folderId = folderName ? options?.folderMap?.get(folderName) : void 0;
21610
- const updated = await updateVaultMemoryOp(vaultCtx, id, {
21669
+ const updated = await updateVaultMemoryOp(ctx, id, {
21611
21670
  content,
21612
21671
  embedding: null,
21613
21672
  folderId,
@@ -21622,7 +21681,7 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
21622
21681
  content,
21623
21682
  embeddingOptions,
21624
21683
  cache,
21625
- vaultCtx,
21684
+ ctx,
21626
21685
  id,
21627
21686
  updated.updatedAt
21628
21687
  ).catch(() => {
@@ -21642,18 +21701,22 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
21642
21701
  await notifyWritten(options, input, outcome2);
21643
21702
  return describeWriteOutcome(outcome2);
21644
21703
  }
21645
- const created = await createVaultMemoryOp(vaultCtx, {
21704
+ const created = store ? await store.create({
21705
+ content,
21706
+ scope,
21707
+ ...factType !== void 0 && { factType }
21708
+ }) : await createVaultMemoryOp(ctx, {
21646
21709
  content,
21647
21710
  scope,
21648
21711
  folderId,
21649
21712
  ...factType !== void 0 && { factType }
21650
21713
  });
21651
- if (embeddingOptions && cache) {
21714
+ if (ctx && embeddingOptions && cache) {
21652
21715
  eagerEmbedContent(
21653
21716
  content,
21654
21717
  embeddingOptions,
21655
21718
  cache,
21656
- vaultCtx,
21719
+ ctx,
21657
21720
  created.uniqueId,
21658
21721
  created.updatedAt
21659
21722
  ).catch(() => {
@@ -21985,6 +22048,128 @@ function useCredits(options = {}) {
21985
22048
 
21986
22049
  // src/react/useModels.ts
21987
22050
  import { useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
22051
+ var MODELS_CACHE_TTL_MS = 5 * 60 * 1e3;
22052
+ var modelsCache = /* @__PURE__ */ new Map();
22053
+ var modelsInFlight = /* @__PURE__ */ new Map();
22054
+ var cacheGeneration = 0;
22055
+ function clearModelsCache() {
22056
+ cacheGeneration++;
22057
+ modelsCache.clear();
22058
+ modelsInFlight.clear();
22059
+ }
22060
+ function pruneStaleTokenEntries(newKey) {
22061
+ const [newBaseUrl, newProvider] = JSON.parse(newKey);
22062
+ for (const existingKey of modelsCache.keys()) {
22063
+ if (existingKey === newKey) continue;
22064
+ const [existingBaseUrl, existingProvider] = JSON.parse(existingKey);
22065
+ if (existingBaseUrl === newBaseUrl && existingProvider === newProvider) {
22066
+ modelsCache.delete(existingKey);
22067
+ }
22068
+ }
22069
+ }
22070
+ function fingerprintToken(token) {
22071
+ if (!token) return "anon";
22072
+ let h1 = 3735928559;
22073
+ let h2 = 1103547991;
22074
+ for (let i = 0; i < token.length; i++) {
22075
+ const ch = token.charCodeAt(i);
22076
+ h1 = Math.imul(h1 ^ ch, 2654435761);
22077
+ h2 = Math.imul(h2 ^ ch, 1597334677);
22078
+ }
22079
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
22080
+ h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
22081
+ return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
22082
+ }
22083
+ function modelsCacheKey(baseUrl, provider, token) {
22084
+ return JSON.stringify([baseUrl, provider ?? null, fingerprintToken(token)]);
22085
+ }
22086
+ async function fetchAllModelPages(baseUrl, provider, headers, previous, signal) {
22087
+ const pages = /* @__PURE__ */ new Map();
22088
+ const models = [];
22089
+ let pageToken;
22090
+ do {
22091
+ const pageKey = pageToken ?? "";
22092
+ const stored2 = previous?.pages.get(pageKey);
22093
+ const request = (etag) => getApiV1Models({
22094
+ baseUrl,
22095
+ headers: etag ? { ...headers, "If-None-Match": etag } : headers,
22096
+ query: { provider, page_token: pageToken },
22097
+ signal
22098
+ });
22099
+ let response = await request(stored2?.etag);
22100
+ if (stored2?.etag && !response.response && response.error) {
22101
+ response = await request();
22102
+ }
22103
+ let page;
22104
+ if (response.response?.status === 304) {
22105
+ if (!stored2) throw new Error("Failed to fetch models");
22106
+ page = stored2;
22107
+ } else {
22108
+ if (response.error) {
22109
+ const errorMsg = response.error.error ?? "Failed to fetch models";
22110
+ throw new Error(errorMsg);
22111
+ }
22112
+ page = {
22113
+ body: response.data ?? {},
22114
+ etag: response.response?.headers?.get("ETag") ?? void 0
22115
+ };
22116
+ }
22117
+ pages.set(pageKey, page);
22118
+ models.push(...page.body.data || []);
22119
+ pageToken = page.body.next_page_token;
22120
+ } while (pageToken);
22121
+ return { pages, models, fetchedAt: Date.now() };
22122
+ }
22123
+ function loadModels(key, baseUrl, provider, headers, force, signal) {
22124
+ const cached = modelsCache.get(key);
22125
+ if (cached && !force && Date.now() - cached.fetchedAt < MODELS_CACHE_TTL_MS) {
22126
+ return Promise.resolve([...cached.models]);
22127
+ }
22128
+ const shared = (force ? void 0 : modelsInFlight.get(key)) ?? startSharedRequest(key, baseUrl, provider, headers, cached);
22129
+ return waitForSharedRequest(key, shared, signal).then((models) => [...models]);
22130
+ }
22131
+ function startSharedRequest(key, baseUrl, provider, headers, previous) {
22132
+ const controller = new AbortController();
22133
+ const generation = cacheGeneration;
22134
+ const shared = {
22135
+ controller,
22136
+ waiters: 0,
22137
+ promise: Promise.resolve([])
22138
+ };
22139
+ shared.promise = fetchAllModelPages(baseUrl, provider, headers, previous, controller.signal).then((entry) => {
22140
+ if (modelsInFlight.get(key) === shared && generation === cacheGeneration) {
22141
+ pruneStaleTokenEntries(key);
22142
+ modelsCache.set(key, entry);
22143
+ }
22144
+ return entry.models;
22145
+ }).finally(() => {
22146
+ if (modelsInFlight.get(key) === shared) modelsInFlight.delete(key);
22147
+ });
22148
+ modelsInFlight.set(key, shared);
22149
+ return shared;
22150
+ }
22151
+ function waitForSharedRequest(key, shared, signal) {
22152
+ shared.waiters++;
22153
+ let left = false;
22154
+ const leave = () => {
22155
+ if (left) return;
22156
+ left = true;
22157
+ shared.waiters--;
22158
+ if (shared.waiters === 0) {
22159
+ shared.controller.abort();
22160
+ if (modelsInFlight.get(key) === shared) modelsInFlight.delete(key);
22161
+ }
22162
+ };
22163
+ if (signal.aborted) {
22164
+ leave();
22165
+ } else {
22166
+ signal.addEventListener("abort", leave, { once: true });
22167
+ }
22168
+ return shared.promise.finally(() => {
22169
+ left = true;
22170
+ signal.removeEventListener("abort", leave);
22171
+ });
22172
+ }
21988
22173
  function useModels(options = {}) {
21989
22174
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
21990
22175
  const [models, setModels] = useState2([]);
@@ -22007,7 +22192,7 @@ function useModels(options = {}) {
22007
22192
  }
22008
22193
  };
22009
22194
  }, []);
22010
- const fetchModels = useCallback2(async () => {
22195
+ const fetchModels = useCallback2(async (force = false) => {
22011
22196
  if (abortControllerRef.current) {
22012
22197
  abortControllerRef.current.abort();
22013
22198
  }
@@ -22026,35 +22211,17 @@ function useModels(options = {}) {
22026
22211
  if (token) {
22027
22212
  headers["Authorization"] = `Bearer ${token}`;
22028
22213
  }
22029
- let allModels = [];
22030
- let nextPageToken;
22031
- do {
22032
- if (signal.aborted) return;
22033
- const response = await getApiV1Models({
22034
- baseUrl: baseUrlRef.current,
22035
- headers,
22036
- query: {
22037
- provider: providerRef.current,
22038
- page_token: nextPageToken
22039
- },
22040
- signal
22041
- });
22042
- if (response.error) {
22043
- const errorMsg = response.error.error ?? "Failed to fetch models";
22044
- throw new Error(errorMsg);
22045
- }
22046
- if (response.data) {
22047
- const newModels = response.data.data || [];
22048
- allModels = [...allModels, ...newModels];
22049
- nextPageToken = response.data.next_page_token;
22050
- }
22051
- } while (nextPageToken);
22214
+ const baseUrl2 = baseUrlRef.current;
22215
+ const provider2 = providerRef.current;
22216
+ const key = modelsCacheKey(baseUrl2, provider2, token);
22217
+ const allModels = await loadModels(key, baseUrl2, provider2, headers, force, signal);
22052
22218
  if (signal.aborted) return;
22053
22219
  setModels(allModels);
22054
22220
  } catch (err) {
22055
22221
  if (err instanceof Error && err.name === "AbortError") {
22056
22222
  return;
22057
22223
  }
22224
+ if (signal.aborted) return;
22058
22225
  setError(err instanceof Error ? err : new Error(String(err)));
22059
22226
  } finally {
22060
22227
  if (!signal.aborted) {
@@ -22067,7 +22234,7 @@ function useModels(options = {}) {
22067
22234
  }, []);
22068
22235
  const refetch = useCallback2(async () => {
22069
22236
  setModels([]);
22070
- await fetchModels();
22237
+ await fetchModels(true);
22071
22238
  }, [fetchModels]);
22072
22239
  const hasFetchedRef = useRef2(false);
22073
22240
  useEffect2(() => {
@@ -23932,6 +24099,8 @@ onClearAllEncryptionState(resetRecentToolSets);
23932
24099
  // src/expo/useChatStorage.ts
23933
24100
  var CONVERSATION_REDACTOR_LIMIT = 50;
23934
24101
  var NO_CONVERSATION_KEY = "__no_conversation__";
24102
+ var NO_STORE_FOLDERS = "Folders are not supported with a memoryStore";
24103
+ var NO_STORE_MASK = "piiRedaction needs a memoryStore built with embeddingOptions.maskInput";
23935
24104
  var conversationRedactors = /* @__PURE__ */ new Map();
23936
24105
  var clientToolFilterCache = /* @__PURE__ */ new Map();
23937
24106
  function getConversationRedactor(conversationId, nerDetector) {
@@ -24033,6 +24202,7 @@ function useChatStorage(options) {
24033
24202
  signMessage,
24034
24203
  embeddedWalletSigner,
24035
24204
  getWalletAddress,
24205
+ memoryStore,
24036
24206
  enableQueue = true,
24037
24207
  autoFlushOnKeyAvailable = true,
24038
24208
  extraToolSets,
@@ -24073,6 +24243,7 @@ function useChatStorage(options) {
24073
24243
  [resolvedPiiRedaction]
24074
24244
  );
24075
24245
  const maskEmbeddingInput = isPiiRedactor(resolvedPiiRedaction) ? maskForEmbedding : void 0;
24246
+ const storeMaskMissing = memoryStore !== void 0 && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
24076
24247
  const messagesCollection = useMemo(() => database.get("history"), [database]);
24077
24248
  const conversationsCollection = useMemo(
24078
24249
  () => database.get("conversations"),
@@ -24321,6 +24492,15 @@ function useChatStorage(options) {
24321
24492
  }, [vaultEmbeddingCache]);
24322
24493
  const retainVaultMemory = useCallback4(
24323
24494
  async (input) => {
24495
+ if (memoryStore) {
24496
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
24497
+ if (input.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
24498
+ return memoryStore.retain(input.content, {
24499
+ source: "manual",
24500
+ scope: input.scope,
24501
+ ...input.factType !== void 0 && { factType: input.factType }
24502
+ });
24503
+ }
24324
24504
  if (!getToken) {
24325
24505
  throw new Error("getToken is required to retain a vault memory");
24326
24506
  }
@@ -24344,37 +24524,56 @@ function useChatStorage(options) {
24344
24524
  }
24345
24525
  );
24346
24526
  },
24347
- [vaultCtx, getToken, baseUrl, embeddingModel, maskEmbeddingInput, vaultEmbeddingCache]
24527
+ [
24528
+ vaultCtx,
24529
+ getToken,
24530
+ baseUrl,
24531
+ embeddingModel,
24532
+ maskEmbeddingInput,
24533
+ vaultEmbeddingCache,
24534
+ memoryStore,
24535
+ storeMaskMissing
24536
+ ]
24348
24537
  );
24349
24538
  const createMemoryVaultTool2 = useCallback4(
24350
24539
  (options2) => {
24540
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
24351
24541
  return createMemoryVaultTool(
24352
- vaultCtx,
24353
- getToken ? { write: retainVaultMemory, ...options2 } : options2
24542
+ memoryStore ?? vaultCtx,
24543
+ getToken || memoryStore ? { write: retainVaultMemory, ...options2 } : options2
24354
24544
  );
24355
24545
  },
24356
- [vaultCtx, getToken, retainVaultMemory]
24546
+ [vaultCtx, getToken, retainVaultMemory, memoryStore, storeMaskMissing]
24357
24547
  );
24358
24548
  const createRecallTool2 = useCallback4(
24359
24549
  (toolOptions, callbacks) => {
24360
- if (!getToken) {
24550
+ if (!getToken && !memoryStore) {
24361
24551
  throw new Error("getToken is required for recall tool");
24362
24552
  }
24363
24553
  const resolvedToolOptions = toolOptions?.excludeConversationId !== void 0 || !currentConversationId ? toolOptions : { ...toolOptions, excludeConversationId: currentConversationId };
24554
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
24555
+ if (memoryStore && resolvedToolOptions?.folderId !== void 0)
24556
+ throw new Error(NO_STORE_FOLDERS);
24557
+ const embeddingOptions = {
24558
+ getToken,
24559
+ baseUrl,
24560
+ model: embeddingModel,
24561
+ maskInput: maskEmbeddingInput
24562
+ };
24364
24563
  return createRecallTool(
24365
- {
24564
+ memoryStore ? {
24565
+ factSource: memoryStore.factSource,
24566
+ ...getToken && { storageCtx },
24567
+ embeddingOptions,
24568
+ chunkCache: chunkVectorCacheRef.current
24569
+ } : {
24366
24570
  vaultCtx,
24367
24571
  storageCtx,
24368
- embeddingOptions: {
24369
- getToken,
24370
- baseUrl,
24371
- model: embeddingModel,
24372
- maskInput: maskEmbeddingInput
24373
- },
24572
+ embeddingOptions,
24374
24573
  vaultCache: vaultEmbeddingCache,
24375
24574
  chunkCache: chunkVectorCacheRef.current
24376
24575
  },
24377
- resolvedToolOptions,
24576
+ memoryStore ? { ...resolvedToolOptions, memoryStore } : resolvedToolOptions,
24378
24577
  callbacks
24379
24578
  );
24380
24579
  },
@@ -24386,12 +24585,14 @@ function useChatStorage(options) {
24386
24585
  embeddingModel,
24387
24586
  currentConversationId,
24388
24587
  maskEmbeddingInput,
24389
- vaultEmbeddingCache
24588
+ vaultEmbeddingCache,
24589
+ memoryStore,
24590
+ storeMaskMissing
24390
24591
  ]
24391
24592
  );
24392
24593
  const recallFn = useCallback4(
24393
24594
  async (query, options2) => {
24394
- if (!getToken) {
24595
+ if (!getToken && !memoryStore) {
24395
24596
  return {
24396
24597
  memories: [],
24397
24598
  usedBudget: options2?.budget ?? "low",
@@ -24400,17 +24601,25 @@ function useChatStorage(options) {
24400
24601
  };
24401
24602
  }
24402
24603
  const resolvedOptions = options2?.excludeConversationId !== void 0 || !currentConversationId ? options2 : { ...options2, excludeConversationId: currentConversationId };
24604
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
24605
+ if (memoryStore && resolvedOptions?.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
24606
+ const embeddingOptions = {
24607
+ getToken,
24608
+ baseUrl,
24609
+ model: embeddingModel,
24610
+ maskInput: maskEmbeddingInput
24611
+ };
24403
24612
  return recall(
24404
24613
  query,
24405
- {
24614
+ memoryStore ? {
24615
+ factSource: memoryStore.factSource,
24616
+ ...getToken && { storageCtx },
24617
+ embeddingOptions,
24618
+ chunkCache: chunkVectorCacheRef.current
24619
+ } : {
24406
24620
  vaultCtx,
24407
24621
  storageCtx,
24408
- embeddingOptions: {
24409
- getToken,
24410
- baseUrl,
24411
- model: embeddingModel,
24412
- maskInput: maskEmbeddingInput
24413
- },
24622
+ embeddingOptions,
24414
24623
  vaultCache: vaultEmbeddingCache,
24415
24624
  chunkCache: chunkVectorCacheRef.current
24416
24625
  },
@@ -24425,20 +24634,27 @@ function useChatStorage(options) {
24425
24634
  embeddingModel,
24426
24635
  currentConversationId,
24427
24636
  maskEmbeddingInput,
24428
- vaultEmbeddingCache
24637
+ vaultEmbeddingCache,
24638
+ memoryStore,
24639
+ storeMaskMissing
24429
24640
  ]
24430
24641
  );
24431
24642
  const getVaultMemories = useCallback4(
24432
24643
  (options2) => {
24433
- return getAllVaultMemoriesOp(vaultCtx, options2);
24644
+ if (!memoryStore) return getAllVaultMemoriesOp(vaultCtx, options2);
24645
+ const { folderId, levels, kinds, ...listOptions } = options2 ?? {};
24646
+ if (folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
24647
+ if (levels !== void 0 || kinds !== void 0)
24648
+ throw new Error("level and kind filters are not supported with a memoryStore");
24649
+ return memoryStore.list(listOptions);
24434
24650
  },
24435
- [vaultCtx]
24651
+ [vaultCtx, memoryStore]
24436
24652
  );
24437
24653
  const deleteVaultMemory = useCallback4(
24438
24654
  (id) => {
24439
- return deleteVaultMemoryOp(vaultCtx, id);
24655
+ return memoryStore ? memoryStore.delete(id) : deleteVaultMemoryOp(vaultCtx, id);
24440
24656
  },
24441
- [vaultCtx]
24657
+ [vaultCtx, memoryStore]
24442
24658
  );
24443
24659
  const {
24444
24660
  isLoading,
@@ -25803,6 +26019,7 @@ export {
25803
26019
  clearConversationMemoriesOp,
25804
26020
  clearEncryptionKey,
25805
26021
  clearLazyTitleCache,
26022
+ clearModelsCache,
25806
26023
  clearServerToolsCache,
25807
26024
  consoleLogger,
25808
26025
  conversationMemoryToStored,