@anuma/sdk 3.11.1 → 3.11.3

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.
@@ -5798,6 +5798,17 @@ var init_mmr = __esm({
5798
5798
  }
5799
5799
  });
5800
5800
 
5801
+ // src/lib/memory/recallConstants.ts
5802
+ var RECALL_TOOL_NAME, RECALL_MAX_LIMIT, EMBEDDINGS_DEGRADED_EMPTY;
5803
+ var init_recallConstants = __esm({
5804
+ "src/lib/memory/recallConstants.ts"() {
5805
+ "use strict";
5806
+ RECALL_TOOL_NAME = "recall_memory";
5807
+ RECALL_MAX_LIMIT = 50;
5808
+ EMBEDDINGS_DEGRADED_EMPTY = "Semantic memory search is temporarily unavailable, so only keyword matching ran and it found no matches. Do not conclude the user has no such memory \u2014 say the memory lookup was degraded, or retry with different keywords.";
5809
+ }
5810
+ });
5811
+
5801
5812
  // src/lib/memory/recency.ts
5802
5813
  function recencyMultiplier(updatedAt, opts = {}) {
5803
5814
  const noDate = opts.noDateMultiplier ?? DEFAULT_NO_DATE_MULTIPLIER;
@@ -6845,6 +6856,9 @@ async function recall(query, ctx, options = {}) {
6845
6856
  let vaultSize;
6846
6857
  let didRerank = false;
6847
6858
  let hadV2Head = false;
6859
+ let embeddingsUnavailable = false;
6860
+ let chunkEmbedFailed = false;
6861
+ let factLaneRankedOnCosine = false;
6848
6862
  const emitDiagnostics = (candidateCount) => {
6849
6863
  const cb = options.onDiagnostics;
6850
6864
  if (!cb) return;
@@ -6853,6 +6867,7 @@ async function recall(query, ctx, options = {}) {
6853
6867
  degraded.push("rerank-unavailable");
6854
6868
  }
6855
6869
  if (flags.decompose && !decomposeAvailable) degraded.push("decompose-unavailable");
6870
+ if (embeddingsUnavailable) degraded.push("embeddings-unavailable");
6856
6871
  const diagnostics = {
6857
6872
  usedBudget,
6858
6873
  reranked: didRerank,
@@ -6883,7 +6898,26 @@ async function recall(query, ctx, options = {}) {
6883
6898
  const graphRefiner = flags.traverse && options.graphRefine && options.decomposeOptions ? createLlmNeighborRefiner(options.decomposeOptions) : void 0;
6884
6899
  const prepStart = nowMs();
6885
6900
  const [queryEmbedding, entityRanking, temporalRanking] = await Promise.all([
6886
- needsChunkEmbedding ? generateEmbedding(query, ctx.embeddingOptions) : Promise.resolve(void 0),
6901
+ // The chunk lane is cosine-only — `searchChunksOp` needs a real vector, and
6902
+ // there is no lexical fallback for it — so an embeddings outage must SKIP the
6903
+ // lane, not reject this shared Promise.all and take the primary fact lane
6904
+ // (which BM25 can still serve) down with it. Mirrors safeLane's posture.
6905
+ needsChunkEmbedding ? generateEmbedding(query, ctx.embeddingOptions).then((vec) => {
6906
+ if (vec.length === 0) {
6907
+ getLogger().warn(
6908
+ "[memory/recall] chunk-lane query embedding came back empty; skipping the chunk lane"
6909
+ );
6910
+ chunkEmbedFailed = true;
6911
+ return void 0;
6912
+ }
6913
+ return vec;
6914
+ }).catch((err) => {
6915
+ getLogger().warn(
6916
+ `[memory/recall] chunk-lane query embedding failed; skipping the chunk lane: ${err instanceof Error ? err.message : String(err)}`
6917
+ );
6918
+ chunkEmbedFailed = true;
6919
+ return void 0;
6920
+ }) : Promise.resolve(void 0),
6887
6921
  // The graph + temporal lanes are AUXILIARY (RRF side-signals). A transient
6888
6922
  // WatermelonDB throw in either must NOT reject this Promise.all and take
6889
6923
  // PRIMARY cosine/BM25 recall down with it — degrade the failing lane to an
@@ -6908,7 +6942,9 @@ async function recall(query, ctx, options = {}) {
6908
6942
  results,
6909
6943
  vaultSize: size,
6910
6944
  reranked,
6911
- hadV2Head: v2Head
6945
+ hadV2Head: v2Head,
6946
+ embeddingsUnavailable: factEmbeddingsUnavailable,
6947
+ rankedOnCosine: factRankedOnCosine
6912
6948
  } = await searchVaultMemoriesWithSize(
6913
6949
  query,
6914
6950
  ctx.vaultCtx,
@@ -6965,8 +7001,11 @@ async function recall(query, ctx, options = {}) {
6965
7001
  vaultSize = size;
6966
7002
  didRerank = reranked;
6967
7003
  hadV2Head = v2Head;
7004
+ if (factEmbeddingsUnavailable) embeddingsUnavailable = true;
7005
+ factLaneRankedOnCosine = factRankedOnCosine;
6968
7006
  factLaneMs = nowMs() - factStart;
6969
7007
  }
7008
+ if (chunkEmbedFailed && !factLaneRankedOnCosine) embeddingsUnavailable = true;
6970
7009
  if (types.includes("chunk") && ctx.storageCtx && queryEmbedding) {
6971
7010
  const chunkStart = nowMs();
6972
7011
  const chunkMinScore = options.minScore ?? DEFAULT_CHUNK_MIN_SCORE;
@@ -7729,6 +7768,24 @@ async function eagerEmbedContent(content, embeddingOptions, cache, vaultCtx, mem
7729
7768
  );
7730
7769
  }
7731
7770
  }
7771
+ async function embedQueryOrDegrade(query, embeddingOptions, onDegraded) {
7772
+ try {
7773
+ const embedding = await generateEmbedding(query, embeddingOptions);
7774
+ if (embedding.length === 0) {
7775
+ getLogger().warn(
7776
+ "memoryVault: query embedding came back empty \u2014 falling back to BM25-only ranking for this search"
7777
+ );
7778
+ onDegraded?.();
7779
+ }
7780
+ return embedding;
7781
+ } catch (err) {
7782
+ getLogger().warn(
7783
+ "memoryVault: query embedding failed \u2014 falling back to BM25-only ranking for this search: " + (err instanceof Error ? err.message : String(err))
7784
+ );
7785
+ onDegraded?.();
7786
+ return [];
7787
+ }
7788
+ }
7732
7789
  function admitVaultProjections(queryEmbedding, vectored, k) {
7733
7790
  return vectored.map((it) => ({ it, score: cosineSimilarity(queryEmbedding, it.embedding) })).sort((a, b) => b.score - a.score || b.it.updatedAt.getTime() - a.it.updatedAt.getTime()).slice(0, k).map((s) => s.it.uniqueId);
7734
7791
  }
@@ -7740,23 +7797,36 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
7740
7797
  const hydrateOpts = queryOpts.includeArchived ? { includeArchived: true } : void 0;
7741
7798
  const vaultSize = keys.length;
7742
7799
  if (keys.length === 0) {
7743
- return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7800
+ return {
7801
+ memories: [],
7802
+ embeddedItems: [],
7803
+ queryEmbedding: [],
7804
+ vaultSize: 0,
7805
+ laneEmbedFailed: false
7806
+ };
7744
7807
  }
7745
- const queryEmbedding = await generateEmbedding(query, embeddingOptions);
7808
+ const queryEmbedding = await embedQueryOrDegrade(
7809
+ query,
7810
+ embeddingOptions,
7811
+ opts.onEmbeddingDegraded
7812
+ );
7813
+ const embeddingsDegraded = queryEmbedding.length === 0;
7746
7814
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
7747
7815
  const vectored = [];
7748
7816
  const missIds = [];
7749
7817
  const noVectorIds = [];
7750
7818
  const keyById = new Map(keys.map((k2) => [k2.uniqueId, k2]));
7751
- for (const k2 of keys) {
7752
- const cached = cache.get(k2.uniqueId);
7753
- if (cached && cached.length === queryEmbedding.length) {
7754
- vectored.push({ uniqueId: k2.uniqueId, embedding: cached, updatedAt: k2.updatedAt });
7755
- continue;
7819
+ if (!embeddingsDegraded) {
7820
+ for (const k2 of keys) {
7821
+ const cached = cache.get(k2.uniqueId);
7822
+ if (cached && cached.length === queryEmbedding.length) {
7823
+ vectored.push({ uniqueId: k2.uniqueId, embedding: cached, updatedAt: k2.updatedAt });
7824
+ continue;
7825
+ }
7826
+ const modelCompatible = (k2.embeddingModel ?? currentModel) === currentModel;
7827
+ if (modelCompatible) missIds.push(k2.uniqueId);
7828
+ else noVectorIds.push(k2.uniqueId);
7756
7829
  }
7757
- const modelCompatible = (k2.embeddingModel ?? currentModel) === currentModel;
7758
- if (modelCompatible) missIds.push(k2.uniqueId);
7759
- else noVectorIds.push(k2.uniqueId);
7760
7830
  }
7761
7831
  if (missIds.length > 0) {
7762
7832
  const rows = await getVaultEmbeddingsByIdsOp(vaultCtx, missIds, hydrateOpts);
@@ -7777,6 +7847,7 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
7777
7847
  }
7778
7848
  for (const id of missIds) if (!gotVector.has(id)) noVectorIds.push(id);
7779
7849
  }
7850
+ let laneEmbedFailed = false;
7780
7851
  if (noVectorIds.length > 0) {
7781
7852
  const laneIds = noVectorIds.slice(0, opts.unembeddedCap);
7782
7853
  if (noVectorIds.length > laneIds.length) {
@@ -7788,26 +7859,44 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
7788
7859
  (m) => !isEncrypted(m.content)
7789
7860
  );
7790
7861
  if (laneRows.length > 0) {
7791
- const laneVecs = await generateEmbeddings(
7792
- laneRows.map((m) => m.content),
7793
- embeddingOptions
7794
- );
7795
- laneRows.forEach((m, i) => {
7796
- const vec = Float32Array.from(laneVecs[i]);
7797
- cache.set(m.uniqueId, vec);
7798
- vectored.push({ uniqueId: m.uniqueId, embedding: vec, updatedAt: m.updatedAt });
7799
- updateVaultMemoryEmbeddingOp(
7800
- vaultCtx,
7801
- m.uniqueId,
7802
- JSON.stringify(laneVecs[i]),
7803
- currentModel
7804
- ).catch(() => {
7862
+ let laneVecs;
7863
+ try {
7864
+ laneVecs = await generateEmbeddings(
7865
+ laneRows.map((m) => m.content),
7866
+ embeddingOptions
7867
+ );
7868
+ } catch (err) {
7869
+ laneEmbedFailed = true;
7870
+ getLogger().warn(
7871
+ `memoryVault: un-embedded lane embedding failed for ${laneRows.length} rows \u2014 they rank on BM25 alone for this search: ` + (err instanceof Error ? err.message : String(err))
7872
+ );
7873
+ }
7874
+ if (laneVecs) {
7875
+ const vecs = laneVecs;
7876
+ laneRows.forEach((m, i) => {
7877
+ const vec = Float32Array.from(vecs[i]);
7878
+ cache.set(m.uniqueId, vec);
7879
+ vectored.push({ uniqueId: m.uniqueId, embedding: vec, updatedAt: m.updatedAt });
7880
+ updateVaultMemoryEmbeddingOp(
7881
+ vaultCtx,
7882
+ m.uniqueId,
7883
+ JSON.stringify(vecs[i]),
7884
+ currentModel
7885
+ ).catch(() => {
7886
+ });
7805
7887
  });
7806
- });
7888
+ }
7807
7889
  }
7808
7890
  }
7809
7891
  const k = Math.max(opts.limit * opts.admitFactor, opts.admitFloor);
7810
7892
  const admittedIds = admitVaultProjections(queryEmbedding, vectored, k);
7893
+ if ((embeddingsDegraded || laneEmbedFailed) && admittedIds.length < k) {
7894
+ const already = new Set(admittedIds);
7895
+ for (const key of [...keys].sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())) {
7896
+ if (admittedIds.length >= k) break;
7897
+ if (!already.has(key.uniqueId)) admittedIds.push(key.uniqueId);
7898
+ }
7899
+ }
7811
7900
  const admissionSet = new Set(admittedIds);
7812
7901
  if (opts.forceIncludeIds) {
7813
7902
  for (const id of opts.forceIncludeIds) {
@@ -7835,11 +7924,18 @@ async function buildProjectedCorpus(query, vaultCtx, embeddingOptions, cache, qu
7835
7924
  eventTimeKind: normalizeEventTimeKind(m.eventTimeKind),
7836
7925
  factType: m.factType
7837
7926
  }));
7838
- return { memories, embeddedItems, queryEmbedding, vaultSize };
7927
+ return { memories, embeddedItems, queryEmbedding, vaultSize, laneEmbedFailed };
7839
7928
  }
7840
7929
  async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache, searchOptions) {
7841
7930
  if (!query || typeof query !== "string") {
7842
- return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7931
+ return {
7932
+ memories: [],
7933
+ embeddedItems: [],
7934
+ queryEmbedding: [],
7935
+ vaultSize: 0,
7936
+ embeddingsUnavailable: false,
7937
+ embeddingFailure: false
7938
+ };
7843
7939
  }
7844
7940
  const limit = searchOptions?.limit ?? 5;
7845
7941
  const scopes = searchOptions?.scopes;
@@ -7856,6 +7952,12 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
7856
7952
  let embeddedItems;
7857
7953
  let queryEmbedding;
7858
7954
  let vaultSize;
7955
+ let embeddingsUnavailable = false;
7956
+ let embeddingFailure = false;
7957
+ const onEmbeddingDegraded = () => {
7958
+ embeddingsUnavailable = true;
7959
+ embeddingFailure = true;
7960
+ };
7859
7961
  if (searchOptions?.decryptLast) {
7860
7962
  const forceIncludeIds = [
7861
7963
  ...searchOptions.entityRanking ?? [],
@@ -7866,14 +7968,30 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
7866
7968
  admitFactor: ADMIT_FACTOR,
7867
7969
  admitFloor: ADMIT_FLOOR,
7868
7970
  unembeddedCap: UNEMBEDDED_CAP,
7869
- ...forceIncludeIds.length > 0 && { forceIncludeIds }
7971
+ ...forceIncludeIds.length > 0 && { forceIncludeIds },
7972
+ onEmbeddingDegraded
7870
7973
  });
7871
7974
  if (corpus.vaultSize === 0) {
7872
- return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: 0 };
7975
+ return {
7976
+ memories: [],
7977
+ embeddedItems: [],
7978
+ queryEmbedding: [],
7979
+ vaultSize: 0,
7980
+ embeddingsUnavailable: false,
7981
+ embeddingFailure: false
7982
+ };
7873
7983
  }
7874
7984
  ({ memories, embeddedItems, queryEmbedding, vaultSize } = corpus);
7985
+ if (corpus.laneEmbedFailed) embeddingFailure = true;
7875
7986
  if (memories.length === 0) {
7876
- return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize };
7987
+ return {
7988
+ memories: [],
7989
+ embeddedItems: [],
7990
+ queryEmbedding: [],
7991
+ vaultSize,
7992
+ embeddingsUnavailable,
7993
+ embeddingFailure
7994
+ };
7877
7995
  }
7878
7996
  } else {
7879
7997
  const loaded = await getAllVaultMemoriesOp(
@@ -7888,14 +8006,21 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
7888
8006
  );
7889
8007
  }
7890
8008
  if (memories.length === 0) {
7891
- return { memories: [], embeddedItems: [], queryEmbedding: [], vaultSize: loaded.length };
8009
+ return {
8010
+ memories: [],
8011
+ embeddedItems: [],
8012
+ queryEmbedding: [],
8013
+ vaultSize: loaded.length,
8014
+ embeddingsUnavailable: false,
8015
+ embeddingFailure: false
8016
+ };
7892
8017
  }
7893
- queryEmbedding = await generateEmbedding(query, embeddingOptions);
8018
+ queryEmbedding = await embedQueryOrDegrade(query, embeddingOptions, onEmbeddingDegraded);
7894
8019
  const currentModel = embeddingOptions.model ?? DEFAULT_API_EMBEDDING_MODEL;
7895
8020
  const uncachedTexts = [];
7896
8021
  const uncachedIndices = [];
7897
8022
  let staleReembedCount = 0;
7898
- for (let i = 0; i < memories.length; i++) {
8023
+ for (let i = 0; queryEmbedding.length > 0 && i < memories.length; i++) {
7899
8024
  const content = memories[i].content;
7900
8025
  const memoryId = memories[i].uniqueId;
7901
8026
  const cached = cache.get(memoryId);
@@ -7923,20 +8048,30 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
7923
8048
  );
7924
8049
  }
7925
8050
  if (uncachedTexts.length > 0) {
7926
- const newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
7927
- for (let j = 0; j < uncachedTexts.length; j++) {
7928
- cache.set(memories[uncachedIndices[j]].uniqueId, Float32Array.from(newEmbeddings[j]));
7929
- updateVaultMemoryEmbeddingOp(
7930
- vaultCtx,
7931
- memories[uncachedIndices[j]].uniqueId,
7932
- JSON.stringify(newEmbeddings[j]),
7933
- currentModel
7934
- ).catch(
7935
- // Silently swallow – SDK must not use console.*; embedding will be retried on next search
7936
- () => {
7937
- }
8051
+ let newEmbeddings;
8052
+ try {
8053
+ newEmbeddings = await generateEmbeddings(uncachedTexts, embeddingOptions);
8054
+ } catch (err) {
8055
+ embeddingFailure = true;
8056
+ getLogger().warn(
8057
+ `memoryVault: (re)embedding ${uncachedTexts.length} vault rows failed \u2014 they rank on BM25 alone for this search: ` + (err instanceof Error ? err.message : String(err))
7938
8058
  );
7939
8059
  }
8060
+ if (newEmbeddings) {
8061
+ for (let j = 0; j < uncachedTexts.length; j++) {
8062
+ cache.set(memories[uncachedIndices[j]].uniqueId, Float32Array.from(newEmbeddings[j]));
8063
+ updateVaultMemoryEmbeddingOp(
8064
+ vaultCtx,
8065
+ memories[uncachedIndices[j]].uniqueId,
8066
+ JSON.stringify(newEmbeddings[j]),
8067
+ currentModel
8068
+ ).catch(
8069
+ // Silently swallow – SDK must not use console.*; embedding will be retried on next search
8070
+ () => {
8071
+ }
8072
+ );
8073
+ }
8074
+ }
7940
8075
  }
7941
8076
  embeddedItems = memories.map((m) => ({
7942
8077
  id: m.uniqueId,
@@ -7953,12 +8088,22 @@ async function prepareVaultCandidates(query, vaultCtx, embeddingOptions, cache,
7953
8088
  factType: m.factType
7954
8089
  }));
7955
8090
  }
7956
- return { memories, embeddedItems, queryEmbedding, vaultSize };
8091
+ if (!embeddingsUnavailable && !embeddedItems.some((it) => it.embedding.length > 0)) {
8092
+ embeddingsUnavailable = true;
8093
+ }
8094
+ return {
8095
+ memories,
8096
+ embeddedItems,
8097
+ queryEmbedding,
8098
+ vaultSize,
8099
+ embeddingsUnavailable,
8100
+ embeddingFailure
8101
+ };
7957
8102
  }
7958
8103
  async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions) {
7959
8104
  const limit = searchOptions?.limit ?? 5;
7960
8105
  const minSimilarity = searchOptions?.minSimilarity ?? 0.1;
7961
- const { memories, embeddedItems, queryEmbedding, vaultSize } = prepared;
8106
+ const { memories, embeddedItems, queryEmbedding, vaultSize, embeddingsUnavailable } = prepared;
7962
8107
  if (queryEmbedding.length > 0) {
7963
8108
  const mismatched = embeddedItems.filter(
7964
8109
  (it) => it.embedding.length > 0 && it.embedding.length !== queryEmbedding.length
@@ -7995,7 +8140,8 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
7995
8140
  results: results2,
7996
8141
  vaultSize: out.vaultSize,
7997
8142
  reranked: out.reranked ?? false,
7998
- hadV2Head: out.hadV2Head ?? false
8143
+ hadV2Head: out.hadV2Head ?? false,
8144
+ embeddingsUnavailable
7999
8145
  };
8000
8146
  };
8001
8147
  const rerankStats = { applied: false };
@@ -8018,36 +8164,46 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
8018
8164
  ...searchOptions?.rrfK !== void 0 && { rrfK: searchOptions.rrfK },
8019
8165
  ...searchOptions?.factTypeWeights && { factTypeWeights: searchOptions.factTypeWeights }
8020
8166
  };
8021
- if (useFusion && searchOptions?.decompose === "llm" && searchOptions.decomposeOptions) {
8167
+ if (useFusion && !embeddingsUnavailable && searchOptions?.decompose === "llm" && searchOptions.decomposeOptions) {
8022
8168
  const decomp = await decomposeQuery(query, searchOptions.decomposeOptions);
8023
8169
  if (decomp.mode === "composite") {
8024
- const subEmbeddings = await generateEmbeddings(decomp.subQueries, embeddingOptions);
8025
- const subQueries = decomp.subQueries.map((sq, i) => ({
8026
- query: sq,
8027
- embedding: subEmbeddings[i]
8028
- }));
8029
- const v2HeadStats = { hadResults: false };
8030
- const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
8031
- limit,
8032
- minSimilarity,
8033
- rerank: !!searchOptions.rerank,
8034
- ...searchOptions.rerankTopN !== void 0 && {
8035
- rerankTopN: searchOptions.rerankTopN
8036
- },
8037
- ...searchOptions.ceWeight !== void 0 && { ceWeight: searchOptions.ceWeight },
8038
- ...searchOptions.mmr !== void 0 && { mmr: searchOptions.mmr },
8039
- ...tuning,
8040
- ...searchOptions.entityRanking && { entityRanking: searchOptions.entityRanking },
8041
- ...searchOptions.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
8042
- rerankStats,
8043
- v2HeadStats
8044
- });
8045
- return stampTimestamps({
8046
- results: composite,
8047
- vaultSize,
8048
- reranked: rerankStats.applied,
8049
- hadV2Head: v2HeadStats.hadResults
8050
- });
8170
+ let subEmbeddings;
8171
+ try {
8172
+ subEmbeddings = await generateEmbeddings(decomp.subQueries, embeddingOptions);
8173
+ } catch (err) {
8174
+ getLogger().warn(
8175
+ "memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
8176
+ );
8177
+ subEmbeddings = [];
8178
+ }
8179
+ if (subEmbeddings.length > 0) {
8180
+ const subQueries = decomp.subQueries.map((sq, i) => ({
8181
+ query: sq,
8182
+ embedding: subEmbeddings[i]
8183
+ }));
8184
+ const v2HeadStats = { hadResults: false };
8185
+ const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
8186
+ limit,
8187
+ minSimilarity,
8188
+ rerank: !!searchOptions.rerank,
8189
+ ...searchOptions.rerankTopN !== void 0 && {
8190
+ rerankTopN: searchOptions.rerankTopN
8191
+ },
8192
+ ...searchOptions.ceWeight !== void 0 && { ceWeight: searchOptions.ceWeight },
8193
+ ...searchOptions.mmr !== void 0 && { mmr: searchOptions.mmr },
8194
+ ...tuning,
8195
+ ...searchOptions.entityRanking && { entityRanking: searchOptions.entityRanking },
8196
+ ...searchOptions.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
8197
+ rerankStats,
8198
+ v2HeadStats
8199
+ });
8200
+ return stampTimestamps({
8201
+ results: composite,
8202
+ vaultSize,
8203
+ reranked: rerankStats.applied,
8204
+ hadV2Head: v2HeadStats.hadResults
8205
+ });
8206
+ }
8051
8207
  }
8052
8208
  }
8053
8209
  if (useFusion && searchOptions?.rerank) {
@@ -8098,7 +8254,14 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
8098
8254
  }
8099
8255
  async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, cache, searchOptions) {
8100
8256
  if (!query || typeof query !== "string") {
8101
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
8257
+ return {
8258
+ results: [],
8259
+ vaultSize: 0,
8260
+ reranked: false,
8261
+ hadV2Head: false,
8262
+ embeddingsUnavailable: false,
8263
+ rankedOnCosine: false
8264
+ };
8102
8265
  }
8103
8266
  const prepared = await prepareVaultCandidates(
8104
8267
  query,
@@ -8108,12 +8271,32 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
8108
8271
  searchOptions
8109
8272
  );
8110
8273
  if (prepared.vaultSize === 0) {
8111
- return { results: [], vaultSize: 0, reranked: false, hadV2Head: false };
8274
+ return {
8275
+ results: [],
8276
+ vaultSize: 0,
8277
+ reranked: false,
8278
+ hadV2Head: false,
8279
+ embeddingsUnavailable: prepared.embeddingsUnavailable,
8280
+ rankedOnCosine: false
8281
+ };
8112
8282
  }
8113
8283
  if (prepared.memories.length === 0) {
8114
- return { results: [], vaultSize: prepared.vaultSize, reranked: false, hadV2Head: false };
8284
+ return {
8285
+ results: [],
8286
+ vaultSize: prepared.vaultSize,
8287
+ reranked: false,
8288
+ hadV2Head: false,
8289
+ embeddingsUnavailable: prepared.embeddingsUnavailable,
8290
+ rankedOnCosine: false
8291
+ };
8115
8292
  }
8116
- return rankPreparedVaultCandidates(query, prepared, embeddingOptions, searchOptions);
8293
+ const ranked = await rankPreparedVaultCandidates(
8294
+ query,
8295
+ prepared,
8296
+ embeddingOptions,
8297
+ searchOptions
8298
+ );
8299
+ return { ...ranked, rankedOnCosine: !ranked.embeddingsUnavailable };
8117
8300
  }
8118
8301
  async function searchVaultMemories(query, vaultCtx, embeddingOptions, cache, searchOptions) {
8119
8302
  const { results } = await searchVaultMemoriesWithSize(
@@ -8187,26 +8370,36 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
8187
8370
  const budget = searchOptions?.decompose === "llm" && searchOptions.decomposeOptions ? "high" : searchOptions?.rerank ? "mid" : "low";
8188
8371
  const folderId = searchOptions?.folderId ?? argFolderId;
8189
8372
  if (searchOptions?.useFusion === false) {
8190
- const legacy = await searchVaultMemories(query, vaultCtx, embeddingOptions, cache, {
8191
- limit: requestLimit,
8192
- minSimilarity,
8193
- useFusion: false,
8194
- ...tuningForward,
8195
- ...folderId !== void 0 && { folderId },
8196
- ...searchOptions?.scopes && { scopes: searchOptions.scopes }
8197
- });
8373
+ const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
8374
+ query,
8375
+ vaultCtx,
8376
+ embeddingOptions,
8377
+ cache,
8378
+ {
8379
+ limit: requestLimit,
8380
+ minSimilarity,
8381
+ useFusion: false,
8382
+ ...tuningForward,
8383
+ ...folderId !== void 0 && { folderId },
8384
+ ...searchOptions?.scopes && { scopes: searchOptions.scopes }
8385
+ }
8386
+ );
8198
8387
  if (legacy.length === 0) {
8199
- return "No relevant memories found in the vault.";
8388
+ return embeddingsUnavailable ? EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL : "No relevant memories found in the vault.";
8200
8389
  }
8201
8390
  return formatVaultHits(
8202
8391
  legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
8203
8392
  );
8204
8393
  }
8205
8394
  const { recall: recall2 } = await Promise.resolve().then(() => (init_recall(), recall_exports));
8395
+ let recallDegraded = [];
8206
8396
  const result = await recall2(
8207
8397
  query,
8208
8398
  { vaultCtx, embeddingOptions, vaultCache: cache },
8209
8399
  {
8400
+ onDiagnostics: (d) => {
8401
+ recallDegraded = d.degraded;
8402
+ },
8210
8403
  types: ["fact"],
8211
8404
  limit: requestLimit,
8212
8405
  minScore: minSimilarity,
@@ -8227,7 +8420,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
8227
8420
  return "The memory vault is empty. No memories have been saved yet.";
8228
8421
  }
8229
8422
  if (result.memories.length === 0) {
8230
- return "No relevant memories found in the vault.";
8423
+ return recallDegraded.includes("embeddings-unavailable") ? EMBEDDINGS_DEGRADED_EMPTY : "No relevant memories found in the vault.";
8231
8424
  }
8232
8425
  const formatted = formatVaultHits(
8233
8426
  result.memories.map((m) => ({
@@ -8246,7 +8439,7 @@ ${formatted}`;
8246
8439
  }
8247
8440
  };
8248
8441
  }
8249
- var SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW;
8442
+ var SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
8250
8443
  var init_searchTool = __esm({
8251
8444
  "src/lib/memoryVault/searchTool.ts"() {
8252
8445
  "use strict";
@@ -8254,6 +8447,7 @@ var init_searchTool = __esm({
8254
8447
  init_operations3();
8255
8448
  init_logger();
8256
8449
  init_mmr();
8450
+ init_recallConstants();
8257
8451
  init_recency();
8258
8452
  init_reranker();
8259
8453
  init_rrf();
@@ -8267,6 +8461,7 @@ var init_searchTool = __esm({
8267
8461
  SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;
8268
8462
  SUPERSESSION_BOOST_FACTOR = 0.8;
8269
8463
  SUPERSESSION_MAX_WINDOW = 50;
8464
+ EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL = "Memory search is temporarily unavailable \u2014 the semantic lookup failed and this search mode has no keyword fallback, so no memory search ran at all. Do not conclude the user has no such memory; say the memory lookup was unavailable.";
8270
8465
  }
8271
8466
  });
8272
8467
 
@@ -9646,6 +9841,9 @@ var CompletionsStrategy = class {
9646
9841
  }
9647
9842
  }
9648
9843
  }
9844
+ if (choice.finish_reason) {
9845
+ accumulator.finishReason = choice.finish_reason;
9846
+ }
9649
9847
  if (choice.finish_reason === "tool_calls" || choice.finish_reason === "stop") {
9650
9848
  if (accumulator.toolCalls.size > 0) {
9651
9849
  accumulator.content = mergeXaiInlineParameterTags(
@@ -9728,7 +9926,9 @@ var CompletionsStrategy = class {
9728
9926
  content: finalContent,
9729
9927
  ...toolCalls && { tool_calls: toolCalls }
9730
9928
  },
9731
- finish_reason: toolCalls ? "tool_calls" : "stop"
9929
+ // Prefer what the provider actually said; fall back to the derived
9930
+ // value only when the stream carried no finish_reason at all.
9931
+ finish_reason: accumulator.finishReason ?? (toolCalls ? "tool_calls" : "stop")
9732
9932
  }
9733
9933
  ],
9734
9934
  ...usage && { usage },
@@ -10399,7 +10599,7 @@ var ResponsesStrategy = class {
10399
10599
  }
10400
10600
  return result;
10401
10601
  }
10402
- if (typedChunk.type === "response.completed") {
10602
+ if (typedChunk.type === "response.completed" || typedChunk.type === "response.incomplete") {
10403
10603
  if (typedChunk.response?.usage) {
10404
10604
  const u = typedChunk.response.usage;
10405
10605
  const promptTokens = u.input_tokens ?? u.prompt_tokens ?? 0;
@@ -10415,6 +10615,11 @@ var ResponsesStrategy = class {
10415
10615
  ...creditsExhausted !== void 0 && { credits_exhausted: creditsExhausted }
10416
10616
  };
10417
10617
  }
10618
+ const resp = typedChunk.response;
10619
+ const looksIncomplete = typedChunk.type === "response.incomplete" || resp?.status === "incomplete";
10620
+ if (looksIncomplete && resp?.incomplete_details?.reason === "max_output_tokens") {
10621
+ accumulator.finishReason = "length";
10622
+ }
10418
10623
  if (typedChunk.response?.tools_checksum && !accumulator.toolsChecksum) {
10419
10624
  accumulator.toolsChecksum = typedChunk.response.tools_checksum;
10420
10625
  }
@@ -11951,7 +12156,17 @@ Executing tool: ${toolInfo}
11951
12156
  flushDeAnon();
11952
12157
  currentAccumulator.content += tip;
11953
12158
  }
12159
+ const truncatedToNothing = (acc) => acc.finishReason === "length" && acc.toolCalls.size === 0 && acc.content.trim() === "";
12160
+ const TRUNCATION_ERROR = "Model response was truncated at the output-token limit before it produced any usable content or tool call. Retry with a higher `maxOutputTokens`, or prompt for fewer/smaller tool calls per turn.";
11954
12161
  if (toolIteration > 0) {
12162
+ if (truncatedToNothing(currentAccumulator)) {
12163
+ await fireRunError({ error: TRUNCATION_ERROR, stage: "model" });
12164
+ return {
12165
+ data: buildResponseFinal(currentAccumulator),
12166
+ error: TRUNCATION_ERROR,
12167
+ toolsChecksum: currentAccumulator.toolsChecksum
12168
+ };
12169
+ }
11955
12170
  const finalResponse = buildResponseFinal(currentAccumulator);
11956
12171
  if (onFinish) onFinish(finalResponse);
11957
12172
  await fireRunEnd({
@@ -11965,6 +12180,14 @@ Executing tool: ${toolInfo}
11965
12180
  autoExecutedToolResults: accumulatedToolResults
11966
12181
  };
11967
12182
  }
12183
+ if (truncatedToNothing(accumulator)) {
12184
+ await fireRunError({ error: TRUNCATION_ERROR, stage: "model" });
12185
+ return {
12186
+ data: response,
12187
+ error: TRUNCATION_ERROR,
12188
+ toolsChecksum: accumulator.toolsChecksum
12189
+ };
12190
+ }
11968
12191
  if (onFinish) onFinish(response);
11969
12192
  await fireRunEnd({
11970
12193
  finalContent: finalContentText(accumulator),
@@ -15959,6 +16182,11 @@ async function retain(content, ctx, options = {}) {
15959
16182
  ...options.folderId !== void 0 && { folderId: options.folderId }
15960
16183
  }
15961
16184
  );
16185
+ if (prepared.embeddingFailure || prepared.embeddingsUnavailable) {
16186
+ throw new Error(
16187
+ "retain: embeddings unavailable \u2014 refusing to auto-merge against an inert cosine lane, which would create a duplicate instead of merging into the existing memory. Retry when embeddings recover, or pass enableAutoMerge: false to force a create."
16188
+ );
16189
+ }
15962
16190
  if (options.consolidateOptions) {
15963
16191
  const outcome = await tryConsolidate(trimmed, ctx, options, prepared);
15964
16192
  if (outcome) {
@@ -17210,12 +17438,7 @@ init_recall();
17210
17438
 
17211
17439
  // src/lib/memory/recallTool.ts
17212
17440
  init_recall();
17213
-
17214
- // src/lib/memory/recallConstants.ts
17215
- var RECALL_TOOL_NAME = "recall_memory";
17216
- var RECALL_MAX_LIMIT = 50;
17217
-
17218
- // src/lib/memory/recallTool.ts
17441
+ init_recallConstants();
17219
17442
  var DEFAULT_LIMIT2 = 8;
17220
17443
  var DEFAULT_BUDGET2 = "low";
17221
17444
  function formatEventTime(start, end, kind) {
@@ -17365,7 +17588,11 @@ function createRecallTool(ctx, toolOptions, callbacks) {
17365
17588
  conversationMemories += effectiveLimit;
17366
17589
  let surfaced = 0;
17367
17590
  try {
17591
+ let recallDegraded = [];
17368
17592
  const recallOpts = {
17593
+ onDiagnostics: (d) => {
17594
+ recallDegraded = d.degraded;
17595
+ },
17369
17596
  types: defaultTypes,
17370
17597
  limit: effectiveLimit,
17371
17598
  budget: defaultBudget,
@@ -17397,6 +17624,9 @@ function createRecallTool(ctx, toolOptions, callbacks) {
17397
17624
  }
17398
17625
  }
17399
17626
  surfaced = result.memories.length;
17627
+ if (result.memories.length === 0 && recallDegraded.includes("embeddings-unavailable")) {
17628
+ return EMBEDDINGS_DEGRADED_EMPTY;
17629
+ }
17400
17630
  const formatted = formatRecallResult(result.memories);
17401
17631
  return truncatedByBudget && surfaced > 0 ? `${formatted}
17402
17632
 
@@ -17577,6 +17807,7 @@ init_embeddings();
17577
17807
  init_vector();
17578
17808
  init_observationTrend();
17579
17809
  init_recall();
17810
+ init_recallConstants();
17580
17811
  var DEFAULT_SYNTHESIS_MODEL = "inclusionai/ling-2.6-flash";
17581
17812
  var DEFAULT_FACET_RECALL_LIMIT = 20;
17582
17813
  var DEFAULT_FACET_MAX_TOKENS = 512;
@@ -19276,6 +19507,7 @@ async function preprocessFiles(files, options = {}) {
19276
19507
  }
19277
19508
 
19278
19509
  // src/lib/tools/clientToolSelection.ts
19510
+ init_recallConstants();
19279
19511
  init_generate();
19280
19512
 
19281
19513
  // src/tools/appBuilderPrompt.ts