@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.
@@ -1448,6 +1448,7 @@ __export(index_exports, {
1448
1448
  clearConversationMemoriesOp: () => clearConversationMemoriesOp,
1449
1449
  clearEncryptionKey: () => clearEncryptionKey,
1450
1450
  clearLazyTitleCache: () => clearLazyTitleCache,
1451
+ clearModelsCache: () => clearModelsCache,
1451
1452
  clearServerToolsCache: () => clearServerToolsCache,
1452
1453
  consoleLogger: () => consoleLogger,
1453
1454
  conversationMemoryToStored: () => conversationMemoryToStored,
@@ -5878,15 +5879,17 @@ Build ONLY when the user gives an explicit instruction to build, create, generat
5878
5879
 
5879
5880
  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.
5880
5881
 
5881
- 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.
5882
+ 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.
5883
+
5884
+ 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.
5882
5885
 
5883
5886
  WORKFLOW:
5884
5887
  1. NEVER output code as text or markdown. ALWAYS use tools.
5885
5888
  2. Initial build: state your design brief, then create_file with a "files" array writing ALL files in one call. The preview renders automatically.
5886
5889
  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.
5887
5890
  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.
5888
- 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.
5889
- 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.
5891
+ 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.
5892
+ 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.
5890
5893
  7. Keep responses to a sentence or two. Exception: when responding to critique_design, write a substantive paragraph per rubric question.
5891
5894
 
5892
5895
  STRUCTURE:
@@ -6053,12 +6056,13 @@ function isCacheExpired(cache, expirationMs = DEFAULT_CACHE_EXPIRATION_MS) {
6053
6056
  if (!cache) return true;
6054
6057
  return Date.now() - cache.timestamp > expirationMs;
6055
6058
  }
6056
- function buildCacheEntry(tools, checksum) {
6059
+ function buildCacheEntry(tools, checksum, etag) {
6057
6060
  return {
6058
6061
  tools,
6059
6062
  timestamp: Date.now(),
6060
6063
  version: CACHE_VERSION,
6061
- ...checksum && { checksum }
6064
+ ...checksum && { checksum },
6065
+ ...etag && { etag }
6062
6066
  };
6063
6067
  }
6064
6068
  function writeLocalStorageCache(entry) {
@@ -6093,19 +6097,36 @@ function shouldRefreshTools(responseChecksum, cache = localStorageToolsCache) {
6093
6097
  const cachedChecksum = getToolsChecksum2(cache);
6094
6098
  return cachedChecksum instanceof Promise ? cachedChecksum.then(decide) : decide(cachedChecksum);
6095
6099
  }
6096
- async function fetchServerToolsFromApi(baseUrl, token) {
6097
- const response = await fetch(`${baseUrl}/api/v1/tools`, {
6100
+ async function fetchServerToolsFromApi(baseUrl, authHeaders, etag) {
6101
+ const request = (validator) => fetch(`${baseUrl}/api/v1/tools`, {
6098
6102
  method: "GET",
6099
6103
  headers: {
6100
- Authorization: `Bearer ${token}`,
6101
- "Content-Type": "application/json"
6104
+ ...authHeaders,
6105
+ "Content-Type": "application/json",
6106
+ ...validator && { "If-None-Match": validator }
6102
6107
  }
6103
6108
  });
6109
+ let response;
6110
+ try {
6111
+ response = await request(etag);
6112
+ } catch (error) {
6113
+ if (!etag || !(error instanceof TypeError)) throw error;
6114
+ etag = void 0;
6115
+ response = await request();
6116
+ }
6117
+ if (etag && response.status === 304) {
6118
+ return { notModified: true };
6119
+ }
6104
6120
  if (!response.ok) {
6105
6121
  throw new Error(`Failed to fetch server tools: ${response.status}`);
6106
6122
  }
6107
6123
  const data = await response.json();
6108
- return convertServerToolsResponse(data);
6124
+ const responseEtag = response.headers?.get("ETag") ?? void 0;
6125
+ return {
6126
+ notModified: false,
6127
+ ...convertServerToolsResponse(data),
6128
+ ...responseEtag && { etag: responseEtag }
6129
+ };
6109
6130
  }
6110
6131
  async function getServerTools(options) {
6111
6132
  const {
@@ -6137,34 +6158,30 @@ async function getServerTools(options) {
6137
6158
  try {
6138
6159
  const { BASE_URL: BASE_URL2 } = await Promise.resolve().then(() => (init_clientConfig(), clientConfig_exports));
6139
6160
  const effectiveBaseUrl = baseUrl ?? BASE_URL2;
6161
+ const validator = cached && !forceRefresh ? cached.etag : void 0;
6162
+ let authHeaders;
6140
6163
  if (apiKey) {
6141
- const response = await fetch(`${effectiveBaseUrl}/api/v1/tools`, {
6142
- method: "GET",
6143
- headers: {
6144
- "X-API-Key": apiKey,
6145
- "Content-Type": "application/json"
6146
- }
6147
- });
6148
- if (!response.ok) {
6149
- throw new Error(`Failed to fetch server tools: ${response.status}`);
6164
+ authHeaders = { "X-API-Key": apiKey };
6165
+ } else {
6166
+ if (!getToken) {
6167
+ getLogger().warn("[serverTools] No auth method available for fetching tools");
6168
+ return cached?.tools ?? [];
6150
6169
  }
6151
- const data = await response.json();
6152
- const { tools: tools2, checksum: checksum2 } = convertServerToolsResponse(data);
6153
- await persistCache(buildCacheEntry(tools2, checksum2));
6154
- return tools2;
6155
- }
6156
- if (!getToken) {
6157
- getLogger().warn("[serverTools] No auth method available for fetching tools");
6158
- return cached?.tools ?? [];
6170
+ const token = await getToken();
6171
+ if (!token) {
6172
+ getLogger().warn("[serverTools] No auth token available for fetching tools");
6173
+ return cached?.tools ?? [];
6174
+ }
6175
+ authHeaders = { Authorization: `Bearer ${token}` };
6159
6176
  }
6160
- const token = await getToken();
6161
- if (!token) {
6162
- getLogger().warn("[serverTools] No auth token available for fetching tools");
6163
- return cached?.tools ?? [];
6177
+ const result = await fetchServerToolsFromApi(effectiveBaseUrl, authHeaders, validator);
6178
+ if (result.notModified) {
6179
+ const confirmed = cached;
6180
+ await persistCache({ ...confirmed, timestamp: Date.now() });
6181
+ return confirmed.tools;
6164
6182
  }
6165
- const { tools, checksum } = await fetchServerToolsFromApi(effectiveBaseUrl, token);
6166
- await persistCache(buildCacheEntry(tools, checksum));
6167
- return tools;
6183
+ await persistCache(buildCacheEntry(result.tools, result.checksum, result.etag));
6184
+ return result.tools;
6168
6185
  } catch (error) {
6169
6186
  getLogger().error("[serverTools] Failed to fetch server tools:", error);
6170
6187
  if (cached?.tools) {
@@ -18705,7 +18722,6 @@ async function recall(query, ctx, options = {}) {
18705
18722
  }
18706
18723
  const needsChunkEmbedding = types.includes("chunk") && ctx.storageCtx;
18707
18724
  const wantsTemporal = types.includes("fact") && (ctx.factSource || ctx.vaultCtx);
18708
- const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
18709
18725
  const queryEmbedTotalTimeoutMs = options.queryEmbedTotalTimeoutMs ?? DEFAULT_QUERY_EMBED_TOTAL_TIMEOUT_MS;
18710
18726
  const prepStart = nowMs2();
18711
18727
  let sharedEmbedMs = 0;
@@ -18734,13 +18750,12 @@ async function recall(query, ctx, options = {}) {
18734
18750
  safeLane(
18735
18751
  "graph",
18736
18752
  () => graphLaneFailed = true,
18737
- () => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(query, ctx, flags.traverse, {
18738
- ...options.maxHops !== void 0 && { maxHops: options.maxHops },
18739
- ...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
18740
- ...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
18741
- ...options.rrfK !== void 0 && { rrfK: options.rrfK },
18742
- ...graphRefiner && { refineNeighbors: graphRefiner }
18743
- })
18753
+ () => ctx.factSource ? ctx.factSource.graphRanking(query, flags.traverse, options) : buildGraphLaneRanking(
18754
+ query,
18755
+ ctx,
18756
+ flags.traverse,
18757
+ graphTraversalOptions(options, flags.traverse)
18758
+ )
18744
18759
  ),
18745
18760
  wantsTemporal ? safeLane(
18746
18761
  "temporal",
@@ -18959,6 +18974,16 @@ function toFactMemory(r, now) {
18959
18974
  updatedAt: r.updatedAt ?? /* @__PURE__ */ new Date(0)
18960
18975
  };
18961
18976
  }
18977
+ function graphTraversalOptions(options, traverse) {
18978
+ const refineNeighbors = traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
18979
+ return {
18980
+ ...options.maxHops !== void 0 && { maxHops: options.maxHops },
18981
+ ...options.entityFanout !== void 0 && { entityFanout: options.entityFanout },
18982
+ ...options.nodeBudget !== void 0 && { nodeBudget: options.nodeBudget },
18983
+ ...options.rrfK !== void 0 && { rrfK: options.rrfK },
18984
+ ...refineNeighbors && { refineNeighbors }
18985
+ };
18986
+ }
18962
18987
  async function buildGraphLaneRanking(query, ctx, traverse = false, traversalOptions = {}) {
18963
18988
  const entityCtx = ctx.entityCtx ?? ctx.vaultCtx?.entityCtx;
18964
18989
  if (!entityCtx) return [];
@@ -19124,24 +19149,33 @@ function isDumpQuery(query) {
19124
19149
  return false;
19125
19150
  }
19126
19151
  async function listRecentFacts(ctx, limit, toolOptions) {
19152
+ const store = toolOptions?.memoryStore;
19127
19153
  const vaultCtx = ctx.vaultCtx;
19128
- if (!vaultCtx) return [];
19129
- const ordered = await getVaultRankingProjectionsOp(vaultCtx, {
19154
+ if (!vaultCtx && !store) return [];
19155
+ const read = (ids) => store ? store.list({ memoryIds: ids }) : getVaultMemoriesByIdsOp(vaultCtx, ids);
19156
+ const filters = {
19130
19157
  ...toolOptions?.scopes && { scopes: toolOptions.scopes },
19131
- ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds },
19158
+ ...toolOptions?.memoryIds !== void 0 && { memoryIds: toolOptions.memoryIds }
19159
+ };
19160
+ const project = (size) => store ? store.listProjections({ ...filters, limit: size }) : getVaultRankingProjectionsOp(vaultCtx, {
19161
+ ...filters,
19132
19162
  ...toolOptions?.folderId !== void 0 && { folderId: toolOptions.folderId }
19133
19163
  });
19134
19164
  const readable = [];
19135
- for (let i = 0; i < ordered.length && readable.length < limit; i += limit) {
19136
- const batch = ordered.slice(i, i + limit).map((p) => p.uniqueId);
19137
- const byId = new Map(
19138
- (await getVaultMemoriesByIdsOp(vaultCtx, batch)).map((m) => [m.uniqueId, m])
19139
- );
19140
- for (const id of batch) {
19141
- const m = byId.get(id);
19142
- if (m && !isEncrypted(m.content)) readable.push(m);
19143
- if (readable.length >= limit) break;
19165
+ let start = 0;
19166
+ for (let size = limit; readable.length < limit; size *= 2) {
19167
+ const ordered = await project(size);
19168
+ for (let i = start; i < ordered.length && readable.length < limit; i += limit) {
19169
+ const batch = ordered.slice(i, i + limit).map((p) => p.uniqueId);
19170
+ const byId = new Map((await read(batch)).map((m) => [m.uniqueId, m]));
19171
+ for (const id of batch) {
19172
+ const m = byId.get(id);
19173
+ if (m && !isEncrypted(m.content)) readable.push(m);
19174
+ if (readable.length >= limit) break;
19175
+ }
19144
19176
  }
19177
+ if (!store || ordered.length < size) break;
19178
+ start = ordered.length;
19145
19179
  }
19146
19180
  return readable.map((m) => ({
19147
19181
  id: m.uniqueId,
@@ -19158,6 +19192,8 @@ async function listRecentFacts(ctx, limit, toolOptions) {
19158
19192
  }));
19159
19193
  }
19160
19194
  function createRecallTool(ctx, toolOptions, callbacks) {
19195
+ if (toolOptions?.memoryStore && toolOptions.folderId !== void 0)
19196
+ throw new Error("Folders are not supported with a memoryStore");
19161
19197
  const defaultTypes = toolOptions?.types ?? ["fact", "chunk"];
19162
19198
  const defaultLimit = toolOptions?.limit ?? DEFAULT_LIMIT2;
19163
19199
  const defaultBudget = toolOptions?.budget ?? DEFAULT_BUDGET2;
@@ -19229,7 +19265,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
19229
19265
  let surfaced = 0;
19230
19266
  try {
19231
19267
  let recallDegraded = [];
19232
- const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && ctx.vaultCtx !== void 0;
19268
+ const wantsRecent = args.sort === "recent" && defaultTypes.includes("fact") && (ctx.vaultCtx !== void 0 || toolOptions?.memoryStore !== void 0);
19233
19269
  let result;
19234
19270
  if (wantsRecent) {
19235
19271
  result = { memories: await listRecentFacts(ctx, effectiveLimit, toolOptions) };
@@ -19739,6 +19775,7 @@ function createLocalMemoryStore(options) {
19739
19775
  });
19740
19776
  };
19741
19777
  return {
19778
+ masksEmbeddingInput: options.embeddingOptions.maskInput !== void 0,
19742
19779
  list: (listOptions) => getAllVaultMemoriesOp(vaultCtx, listOptions),
19743
19780
  get: (id) => getVaultMemoryOp(vaultCtx, id),
19744
19781
  listArchived: async () => {
@@ -19820,6 +19857,22 @@ function createLocalMemoryStore(options) {
19820
19857
  { vaultCtx, embeddingOptions: options.embeddingOptions, vaultCache },
19821
19858
  retainOptions
19822
19859
  ),
19860
+ factSource: {
19861
+ search: (query, searchOptions) => searchVaultMemoriesWithSize(
19862
+ query,
19863
+ vaultCtx,
19864
+ options.embeddingOptions,
19865
+ vaultCache,
19866
+ searchOptions
19867
+ ),
19868
+ graphRanking: (query, traverse, recallOptions) => buildGraphLaneRanking(
19869
+ query,
19870
+ { vaultCtx, entityCtx, embeddingOptions: options.embeddingOptions },
19871
+ traverse,
19872
+ graphTraversalOptions(recallOptions, traverse)
19873
+ ),
19874
+ temporalRanking: (query, now) => buildTemporalLaneRanking(query, vaultCtx, now)
19875
+ },
19823
19876
  subscribe: (onChange, subscribeOptions) => {
19824
19877
  const afterFirst = () => {
19825
19878
  let first = true;
@@ -20707,38 +20760,31 @@ function createRemoteMemoryPipeline(options) {
20707
20760
  };
20708
20761
  return { prepare, port };
20709
20762
  };
20710
- return {
20711
- recall: async (query, recallOptions = {}) => {
20763
+ const factSource = {
20764
+ graphRanking: options.graphRanking,
20765
+ temporalRanking: options.temporalRanking,
20766
+ search: async (text13, searchOptions) => {
20712
20767
  const { prepare } = operation("recall");
20713
- return recall(
20714
- query,
20715
- {
20716
- embeddingOptions,
20717
- factSource: {
20718
- graphRanking: options.graphRanking,
20719
- temporalRanking: options.temporalRanking,
20720
- search: async (text13, searchOptions) => {
20721
- const prepared = await prepare(text13, searchOptions);
20722
- const ranked = await rankPreparedVaultCandidates(
20723
- text13,
20724
- prepared,
20725
- embeddingOptions,
20726
- searchOptions
20727
- );
20728
- return {
20729
- ...ranked,
20730
- rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
20731
- decryptLast: true,
20732
- rowsDecrypted: prepared.rowsDecrypted,
20733
- queryEmbedMs: prepared.queryEmbedMs,
20734
- rowsEmbedded: 0
20735
- };
20736
- }
20737
- }
20738
- },
20739
- { ...recallOptions, types: ["fact"] }
20768
+ const prepared = await prepare(text13, searchOptions);
20769
+ const ranked = await rankPreparedVaultCandidates(
20770
+ text13,
20771
+ prepared,
20772
+ embeddingOptions,
20773
+ searchOptions
20740
20774
  );
20741
- },
20775
+ return {
20776
+ ...ranked,
20777
+ rankedOnCosine: prepared.memories.length > 0 && !prepared.embeddingsUnavailable,
20778
+ decryptLast: true,
20779
+ rowsDecrypted: prepared.rowsDecrypted,
20780
+ queryEmbedMs: prepared.queryEmbedMs,
20781
+ rowsEmbedded: 0
20782
+ };
20783
+ }
20784
+ };
20785
+ return {
20786
+ factSource,
20787
+ recall: async (query, recallOptions = {}) => recall(query, { embeddingOptions, factSource }, { ...recallOptions, types: ["fact"] }),
20742
20788
  retain: async (content, retainOptions) => {
20743
20789
  const { port } = operation("retain");
20744
20790
  return retainWithPersistence(
@@ -21100,6 +21146,7 @@ function createRemoteMemoryStore(options) {
21100
21146
  });
21101
21147
  };
21102
21148
  return {
21149
+ masksEmbeddingInput: embeddingOptions.maskInput !== void 0,
21103
21150
  list: async (listOptions = {}) => (await listRows(decrypted, listOptions, listFilters(listOptions), maxOf(listOptions))).map(
21104
21151
  (r) => stored(r.memory)
21105
21152
  ),
@@ -21295,6 +21342,7 @@ function createRemoteMemoryStore(options) {
21295
21342
  })
21296
21343
  ),
21297
21344
  recall: (query, recallOptions) => pipeline.recall(query, recallOptions),
21345
+ factSource: pipeline.factSource,
21298
21346
  retain: async (content, retainOptions) => {
21299
21347
  const result = await pipeline.retain(content, retainOptions);
21300
21348
  if (result.action === "create" || result.action === "supersede") notify("membership");
@@ -23063,19 +23111,20 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
23063
23111
  const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
23064
23112
  const folderId = searchOptions?.folderId ?? argFolderId;
23065
23113
  if (searchOptions?.useFusion === false) {
23066
- const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
23114
+ const legacyOptions = {
23115
+ limit: requestLimit,
23116
+ minSimilarity,
23117
+ useFusion: false,
23118
+ ...tuningForward,
23119
+ ...folderId !== void 0 && { folderId },
23120
+ ...searchOptions?.scopes && { scopes: searchOptions.scopes }
23121
+ };
23122
+ const { results: legacy, embeddingsUnavailable } = "retain" in vaultCtx ? await vaultCtx.factSource.search(query, legacyOptions) : await searchVaultMemoriesWithSize(
23067
23123
  query,
23068
23124
  vaultCtx,
23069
23125
  embeddingOptions,
23070
23126
  cache,
23071
- {
23072
- limit: requestLimit,
23073
- minSimilarity,
23074
- useFusion: false,
23075
- ...tuningForward,
23076
- ...folderId !== void 0 && { folderId },
23077
- ...searchOptions?.scopes && { scopes: searchOptions.scopes }
23078
- }
23127
+ legacyOptions
23079
23128
  );
23080
23129
  if (legacy.length === 0) {
23081
23130
  return embeddingsUnavailable ? EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL : "No relevant memories found in the vault.";
@@ -23094,7 +23143,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
23094
23143
  let recallDegraded = [];
23095
23144
  const result = await recall(
23096
23145
  query,
23097
- { vaultCtx, embeddingOptions, vaultCache: cache },
23146
+ "retain" in vaultCtx ? { factSource: vaultCtx.factSource, embeddingOptions } : { vaultCtx, embeddingOptions, vaultCache: cache },
23098
23147
  {
23099
23148
  onDiagnostics: (d) => {
23100
23149
  recallDegraded = d.degraded;
@@ -23174,8 +23223,10 @@ function describeWriteOutcome(outcome2) {
23174
23223
  }
23175
23224
  }
23176
23225
  function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
23226
+ const store = "retain" in vaultCtx ? vaultCtx : void 0;
23227
+ const ctx = "retain" in vaultCtx ? void 0 : vaultCtx;
23177
23228
  const hasOnSave = !!options?.onSave;
23178
- const folderNames = options?.folderMap ? Array.from(options.folderMap.keys()) : [];
23229
+ const folderNames = !store && options?.folderMap ? Array.from(options.folderMap.keys()) : [];
23179
23230
  return {
23180
23231
  type: "function",
23181
23232
  function: {
@@ -23220,7 +23271,7 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
23220
23271
  let previousContent;
23221
23272
  const scope = options?.scope ?? "private";
23222
23273
  if (isUpdate) {
23223
- const existing = await getVaultMemoryOp(vaultCtx, id);
23274
+ const existing = store ? await store.get(id) : await getVaultMemoryOp(ctx, id);
23224
23275
  if (!existing) {
23225
23276
  return `Error: Memory with ID "${id}" not found. Creating a new memory instead would require a separate call without an ID.`;
23226
23277
  }
@@ -23241,9 +23292,18 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
23241
23292
  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.";
23242
23293
  }
23243
23294
  }
23244
- if (isUpdate) {
23295
+ if (isUpdate && store) {
23296
+ const updated = await store.update(id, {
23297
+ content,
23298
+ ...factType !== void 0 && { factType }
23299
+ });
23300
+ if (!updated) {
23301
+ return `Error: Failed to update memory "${id}".`;
23302
+ }
23303
+ return `Memory updated successfully (ID: ${updated.uniqueId}).`;
23304
+ } else if (isUpdate) {
23245
23305
  const folderId = folderName ? options?.folderMap?.get(folderName) : void 0;
23246
- const updated = await updateVaultMemoryOp(vaultCtx, id, {
23306
+ const updated = await updateVaultMemoryOp(ctx, id, {
23247
23307
  content,
23248
23308
  embedding: null,
23249
23309
  folderId,
@@ -23258,7 +23318,7 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
23258
23318
  content,
23259
23319
  embeddingOptions,
23260
23320
  cache,
23261
- vaultCtx,
23321
+ ctx,
23262
23322
  id,
23263
23323
  updated.updatedAt
23264
23324
  ).catch(() => {
@@ -23278,18 +23338,22 @@ function createMemoryVaultTool(vaultCtx, options, embeddingOptions, cache) {
23278
23338
  await notifyWritten(options, input, outcome2);
23279
23339
  return describeWriteOutcome(outcome2);
23280
23340
  }
23281
- const created = await createVaultMemoryOp(vaultCtx, {
23341
+ const created = store ? await store.create({
23342
+ content,
23343
+ scope,
23344
+ ...factType !== void 0 && { factType }
23345
+ }) : await createVaultMemoryOp(ctx, {
23282
23346
  content,
23283
23347
  scope,
23284
23348
  folderId,
23285
23349
  ...factType !== void 0 && { factType }
23286
23350
  });
23287
- if (embeddingOptions && cache) {
23351
+ if (ctx && embeddingOptions && cache) {
23288
23352
  eagerEmbedContent(
23289
23353
  content,
23290
23354
  embeddingOptions,
23291
23355
  cache,
23292
- vaultCtx,
23356
+ ctx,
23293
23357
  created.uniqueId,
23294
23358
  created.updatedAt
23295
23359
  ).catch(() => {
@@ -23628,6 +23692,128 @@ function useCredits(options = {}) {
23628
23692
  // src/react/useModels.ts
23629
23693
  var import_react3 = require("react");
23630
23694
  init_clientConfig();
23695
+ var MODELS_CACHE_TTL_MS = 5 * 60 * 1e3;
23696
+ var modelsCache = /* @__PURE__ */ new Map();
23697
+ var modelsInFlight = /* @__PURE__ */ new Map();
23698
+ var cacheGeneration = 0;
23699
+ function clearModelsCache() {
23700
+ cacheGeneration++;
23701
+ modelsCache.clear();
23702
+ modelsInFlight.clear();
23703
+ }
23704
+ function pruneStaleTokenEntries(newKey) {
23705
+ const [newBaseUrl, newProvider] = JSON.parse(newKey);
23706
+ for (const existingKey of modelsCache.keys()) {
23707
+ if (existingKey === newKey) continue;
23708
+ const [existingBaseUrl, existingProvider] = JSON.parse(existingKey);
23709
+ if (existingBaseUrl === newBaseUrl && existingProvider === newProvider) {
23710
+ modelsCache.delete(existingKey);
23711
+ }
23712
+ }
23713
+ }
23714
+ function fingerprintToken(token) {
23715
+ if (!token) return "anon";
23716
+ let h1 = 3735928559;
23717
+ let h2 = 1103547991;
23718
+ for (let i = 0; i < token.length; i++) {
23719
+ const ch = token.charCodeAt(i);
23720
+ h1 = Math.imul(h1 ^ ch, 2654435761);
23721
+ h2 = Math.imul(h2 ^ ch, 1597334677);
23722
+ }
23723
+ h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
23724
+ h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
23725
+ return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(36);
23726
+ }
23727
+ function modelsCacheKey(baseUrl, provider, token) {
23728
+ return JSON.stringify([baseUrl, provider ?? null, fingerprintToken(token)]);
23729
+ }
23730
+ async function fetchAllModelPages(baseUrl, provider, headers, previous, signal) {
23731
+ const pages = /* @__PURE__ */ new Map();
23732
+ const models = [];
23733
+ let pageToken;
23734
+ do {
23735
+ const pageKey = pageToken ?? "";
23736
+ const stored2 = previous?.pages.get(pageKey);
23737
+ const request = (etag) => getApiV1Models({
23738
+ baseUrl,
23739
+ headers: etag ? { ...headers, "If-None-Match": etag } : headers,
23740
+ query: { provider, page_token: pageToken },
23741
+ signal
23742
+ });
23743
+ let response = await request(stored2?.etag);
23744
+ if (stored2?.etag && !response.response && response.error) {
23745
+ response = await request();
23746
+ }
23747
+ let page;
23748
+ if (response.response?.status === 304) {
23749
+ if (!stored2) throw new Error("Failed to fetch models");
23750
+ page = stored2;
23751
+ } else {
23752
+ if (response.error) {
23753
+ const errorMsg = response.error.error ?? "Failed to fetch models";
23754
+ throw new Error(errorMsg);
23755
+ }
23756
+ page = {
23757
+ body: response.data ?? {},
23758
+ etag: response.response?.headers?.get("ETag") ?? void 0
23759
+ };
23760
+ }
23761
+ pages.set(pageKey, page);
23762
+ models.push(...page.body.data || []);
23763
+ pageToken = page.body.next_page_token;
23764
+ } while (pageToken);
23765
+ return { pages, models, fetchedAt: Date.now() };
23766
+ }
23767
+ function loadModels(key, baseUrl, provider, headers, force, signal) {
23768
+ const cached = modelsCache.get(key);
23769
+ if (cached && !force && Date.now() - cached.fetchedAt < MODELS_CACHE_TTL_MS) {
23770
+ return Promise.resolve([...cached.models]);
23771
+ }
23772
+ const shared = (force ? void 0 : modelsInFlight.get(key)) ?? startSharedRequest(key, baseUrl, provider, headers, cached);
23773
+ return waitForSharedRequest(key, shared, signal).then((models) => [...models]);
23774
+ }
23775
+ function startSharedRequest(key, baseUrl, provider, headers, previous) {
23776
+ const controller = new AbortController();
23777
+ const generation = cacheGeneration;
23778
+ const shared = {
23779
+ controller,
23780
+ waiters: 0,
23781
+ promise: Promise.resolve([])
23782
+ };
23783
+ shared.promise = fetchAllModelPages(baseUrl, provider, headers, previous, controller.signal).then((entry) => {
23784
+ if (modelsInFlight.get(key) === shared && generation === cacheGeneration) {
23785
+ pruneStaleTokenEntries(key);
23786
+ modelsCache.set(key, entry);
23787
+ }
23788
+ return entry.models;
23789
+ }).finally(() => {
23790
+ if (modelsInFlight.get(key) === shared) modelsInFlight.delete(key);
23791
+ });
23792
+ modelsInFlight.set(key, shared);
23793
+ return shared;
23794
+ }
23795
+ function waitForSharedRequest(key, shared, signal) {
23796
+ shared.waiters++;
23797
+ let left = false;
23798
+ const leave = () => {
23799
+ if (left) return;
23800
+ left = true;
23801
+ shared.waiters--;
23802
+ if (shared.waiters === 0) {
23803
+ shared.controller.abort();
23804
+ if (modelsInFlight.get(key) === shared) modelsInFlight.delete(key);
23805
+ }
23806
+ };
23807
+ if (signal.aborted) {
23808
+ leave();
23809
+ } else {
23810
+ signal.addEventListener("abort", leave, { once: true });
23811
+ }
23812
+ return shared.promise.finally(() => {
23813
+ left = true;
23814
+ signal.removeEventListener("abort", leave);
23815
+ });
23816
+ }
23631
23817
  function useModels(options = {}) {
23632
23818
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
23633
23819
  const [models, setModels] = (0, import_react3.useState)([]);
@@ -23650,7 +23836,7 @@ function useModels(options = {}) {
23650
23836
  }
23651
23837
  };
23652
23838
  }, []);
23653
- const fetchModels = (0, import_react3.useCallback)(async () => {
23839
+ const fetchModels = (0, import_react3.useCallback)(async (force = false) => {
23654
23840
  if (abortControllerRef.current) {
23655
23841
  abortControllerRef.current.abort();
23656
23842
  }
@@ -23669,35 +23855,17 @@ function useModels(options = {}) {
23669
23855
  if (token) {
23670
23856
  headers["Authorization"] = `Bearer ${token}`;
23671
23857
  }
23672
- let allModels = [];
23673
- let nextPageToken;
23674
- do {
23675
- if (signal.aborted) return;
23676
- const response = await getApiV1Models({
23677
- baseUrl: baseUrlRef.current,
23678
- headers,
23679
- query: {
23680
- provider: providerRef.current,
23681
- page_token: nextPageToken
23682
- },
23683
- signal
23684
- });
23685
- if (response.error) {
23686
- const errorMsg = response.error.error ?? "Failed to fetch models";
23687
- throw new Error(errorMsg);
23688
- }
23689
- if (response.data) {
23690
- const newModels = response.data.data || [];
23691
- allModels = [...allModels, ...newModels];
23692
- nextPageToken = response.data.next_page_token;
23693
- }
23694
- } while (nextPageToken);
23858
+ const baseUrl2 = baseUrlRef.current;
23859
+ const provider2 = providerRef.current;
23860
+ const key = modelsCacheKey(baseUrl2, provider2, token);
23861
+ const allModels = await loadModels(key, baseUrl2, provider2, headers, force, signal);
23695
23862
  if (signal.aborted) return;
23696
23863
  setModels(allModels);
23697
23864
  } catch (err) {
23698
23865
  if (err instanceof Error && err.name === "AbortError") {
23699
23866
  return;
23700
23867
  }
23868
+ if (signal.aborted) return;
23701
23869
  setError(err instanceof Error ? err : new Error(String(err)));
23702
23870
  } finally {
23703
23871
  if (!signal.aborted) {
@@ -23710,7 +23878,7 @@ function useModels(options = {}) {
23710
23878
  }, []);
23711
23879
  const refetch = (0, import_react3.useCallback)(async () => {
23712
23880
  setModels([]);
23713
- await fetchModels();
23881
+ await fetchModels(true);
23714
23882
  }, [fetchModels]);
23715
23883
  const hasFetchedRef = (0, import_react3.useRef)(false);
23716
23884
  (0, import_react3.useEffect)(() => {
@@ -25588,6 +25756,8 @@ onClearAllEncryptionState(resetRecentToolSets);
25588
25756
  // src/expo/useChatStorage.ts
25589
25757
  var CONVERSATION_REDACTOR_LIMIT = 50;
25590
25758
  var NO_CONVERSATION_KEY = "__no_conversation__";
25759
+ var NO_STORE_FOLDERS = "Folders are not supported with a memoryStore";
25760
+ var NO_STORE_MASK = "piiRedaction needs a memoryStore built with embeddingOptions.maskInput";
25591
25761
  var conversationRedactors = /* @__PURE__ */ new Map();
25592
25762
  var clientToolFilterCache = /* @__PURE__ */ new Map();
25593
25763
  function getConversationRedactor(conversationId, nerDetector) {
@@ -25689,6 +25859,7 @@ function useChatStorage(options) {
25689
25859
  signMessage,
25690
25860
  embeddedWalletSigner,
25691
25861
  getWalletAddress,
25862
+ memoryStore,
25692
25863
  enableQueue = true,
25693
25864
  autoFlushOnKeyAvailable = true,
25694
25865
  extraToolSets,
@@ -25729,6 +25900,7 @@ function useChatStorage(options) {
25729
25900
  [resolvedPiiRedaction]
25730
25901
  );
25731
25902
  const maskEmbeddingInput = isPiiRedactor(resolvedPiiRedaction) ? maskForEmbedding : void 0;
25903
+ const storeMaskMissing = memoryStore !== void 0 && maskEmbeddingInput !== void 0 && !memoryStore.masksEmbeddingInput;
25732
25904
  const messagesCollection = (0, import_react5.useMemo)(() => database.get("history"), [database]);
25733
25905
  const conversationsCollection = (0, import_react5.useMemo)(
25734
25906
  () => database.get("conversations"),
@@ -25977,6 +26149,15 @@ function useChatStorage(options) {
25977
26149
  }, [vaultEmbeddingCache]);
25978
26150
  const retainVaultMemory = (0, import_react5.useCallback)(
25979
26151
  async (input) => {
26152
+ if (memoryStore) {
26153
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
26154
+ if (input.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
26155
+ return memoryStore.retain(input.content, {
26156
+ source: "manual",
26157
+ scope: input.scope,
26158
+ ...input.factType !== void 0 && { factType: input.factType }
26159
+ });
26160
+ }
25980
26161
  if (!getToken) {
25981
26162
  throw new Error("getToken is required to retain a vault memory");
25982
26163
  }
@@ -26000,37 +26181,56 @@ function useChatStorage(options) {
26000
26181
  }
26001
26182
  );
26002
26183
  },
26003
- [vaultCtx, getToken, baseUrl, embeddingModel, maskEmbeddingInput, vaultEmbeddingCache]
26184
+ [
26185
+ vaultCtx,
26186
+ getToken,
26187
+ baseUrl,
26188
+ embeddingModel,
26189
+ maskEmbeddingInput,
26190
+ vaultEmbeddingCache,
26191
+ memoryStore,
26192
+ storeMaskMissing
26193
+ ]
26004
26194
  );
26005
26195
  const createMemoryVaultTool2 = (0, import_react5.useCallback)(
26006
26196
  (options2) => {
26197
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
26007
26198
  return createMemoryVaultTool(
26008
- vaultCtx,
26009
- getToken ? { write: retainVaultMemory, ...options2 } : options2
26199
+ memoryStore ?? vaultCtx,
26200
+ getToken || memoryStore ? { write: retainVaultMemory, ...options2 } : options2
26010
26201
  );
26011
26202
  },
26012
- [vaultCtx, getToken, retainVaultMemory]
26203
+ [vaultCtx, getToken, retainVaultMemory, memoryStore, storeMaskMissing]
26013
26204
  );
26014
26205
  const createRecallTool2 = (0, import_react5.useCallback)(
26015
26206
  (toolOptions, callbacks) => {
26016
- if (!getToken) {
26207
+ if (!getToken && !memoryStore) {
26017
26208
  throw new Error("getToken is required for recall tool");
26018
26209
  }
26019
26210
  const resolvedToolOptions = toolOptions?.excludeConversationId !== void 0 || !currentConversationId ? toolOptions : { ...toolOptions, excludeConversationId: currentConversationId };
26211
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
26212
+ if (memoryStore && resolvedToolOptions?.folderId !== void 0)
26213
+ throw new Error(NO_STORE_FOLDERS);
26214
+ const embeddingOptions = {
26215
+ getToken,
26216
+ baseUrl,
26217
+ model: embeddingModel,
26218
+ maskInput: maskEmbeddingInput
26219
+ };
26020
26220
  return createRecallTool(
26021
- {
26221
+ memoryStore ? {
26222
+ factSource: memoryStore.factSource,
26223
+ ...getToken && { storageCtx },
26224
+ embeddingOptions,
26225
+ chunkCache: chunkVectorCacheRef.current
26226
+ } : {
26022
26227
  vaultCtx,
26023
26228
  storageCtx,
26024
- embeddingOptions: {
26025
- getToken,
26026
- baseUrl,
26027
- model: embeddingModel,
26028
- maskInput: maskEmbeddingInput
26029
- },
26229
+ embeddingOptions,
26030
26230
  vaultCache: vaultEmbeddingCache,
26031
26231
  chunkCache: chunkVectorCacheRef.current
26032
26232
  },
26033
- resolvedToolOptions,
26233
+ memoryStore ? { ...resolvedToolOptions, memoryStore } : resolvedToolOptions,
26034
26234
  callbacks
26035
26235
  );
26036
26236
  },
@@ -26042,12 +26242,14 @@ function useChatStorage(options) {
26042
26242
  embeddingModel,
26043
26243
  currentConversationId,
26044
26244
  maskEmbeddingInput,
26045
- vaultEmbeddingCache
26245
+ vaultEmbeddingCache,
26246
+ memoryStore,
26247
+ storeMaskMissing
26046
26248
  ]
26047
26249
  );
26048
26250
  const recallFn = (0, import_react5.useCallback)(
26049
26251
  async (query, options2) => {
26050
- if (!getToken) {
26252
+ if (!getToken && !memoryStore) {
26051
26253
  return {
26052
26254
  memories: [],
26053
26255
  usedBudget: options2?.budget ?? "low",
@@ -26056,17 +26258,25 @@ function useChatStorage(options) {
26056
26258
  };
26057
26259
  }
26058
26260
  const resolvedOptions = options2?.excludeConversationId !== void 0 || !currentConversationId ? options2 : { ...options2, excludeConversationId: currentConversationId };
26261
+ if (storeMaskMissing) throw new Error(NO_STORE_MASK);
26262
+ if (memoryStore && resolvedOptions?.folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
26263
+ const embeddingOptions = {
26264
+ getToken,
26265
+ baseUrl,
26266
+ model: embeddingModel,
26267
+ maskInput: maskEmbeddingInput
26268
+ };
26059
26269
  return recall(
26060
26270
  query,
26061
- {
26271
+ memoryStore ? {
26272
+ factSource: memoryStore.factSource,
26273
+ ...getToken && { storageCtx },
26274
+ embeddingOptions,
26275
+ chunkCache: chunkVectorCacheRef.current
26276
+ } : {
26062
26277
  vaultCtx,
26063
26278
  storageCtx,
26064
- embeddingOptions: {
26065
- getToken,
26066
- baseUrl,
26067
- model: embeddingModel,
26068
- maskInput: maskEmbeddingInput
26069
- },
26279
+ embeddingOptions,
26070
26280
  vaultCache: vaultEmbeddingCache,
26071
26281
  chunkCache: chunkVectorCacheRef.current
26072
26282
  },
@@ -26081,20 +26291,27 @@ function useChatStorage(options) {
26081
26291
  embeddingModel,
26082
26292
  currentConversationId,
26083
26293
  maskEmbeddingInput,
26084
- vaultEmbeddingCache
26294
+ vaultEmbeddingCache,
26295
+ memoryStore,
26296
+ storeMaskMissing
26085
26297
  ]
26086
26298
  );
26087
26299
  const getVaultMemories = (0, import_react5.useCallback)(
26088
26300
  (options2) => {
26089
- return getAllVaultMemoriesOp(vaultCtx, options2);
26301
+ if (!memoryStore) return getAllVaultMemoriesOp(vaultCtx, options2);
26302
+ const { folderId, levels, kinds, ...listOptions } = options2 ?? {};
26303
+ if (folderId !== void 0) throw new Error(NO_STORE_FOLDERS);
26304
+ if (levels !== void 0 || kinds !== void 0)
26305
+ throw new Error("level and kind filters are not supported with a memoryStore");
26306
+ return memoryStore.list(listOptions);
26090
26307
  },
26091
- [vaultCtx]
26308
+ [vaultCtx, memoryStore]
26092
26309
  );
26093
26310
  const deleteVaultMemory = (0, import_react5.useCallback)(
26094
26311
  (id) => {
26095
- return deleteVaultMemoryOp(vaultCtx, id);
26312
+ return memoryStore ? memoryStore.delete(id) : deleteVaultMemoryOp(vaultCtx, id);
26096
26313
  },
26097
- [vaultCtx]
26314
+ [vaultCtx, memoryStore]
26098
26315
  );
26099
26316
  const {
26100
26317
  isLoading,
@@ -27460,6 +27677,7 @@ function useChatStorage(options) {
27460
27677
  clearConversationMemoriesOp,
27461
27678
  clearEncryptionKey,
27462
27679
  clearLazyTitleCache,
27680
+ clearModelsCache,
27463
27681
  clearServerToolsCache,
27464
27682
  consoleLogger,
27465
27683
  conversationMemoryToStored,