@anuma/sdk 4.2.1 → 5.0.0
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.
- package/dist/expo/{chunk-3CDSIN22.mjs → chunk-SIMGZQ4P.mjs} +177 -148
- package/dist/expo/index.cjs +110 -71
- package/dist/expo/index.d.mts +69 -19
- package/dist/expo/index.d.ts +69 -19
- package/dist/expo/index.mjs +16 -6
- package/dist/expo/{recall-NARBDQAK.mjs → recall-PIDYDFIQ.mjs} +1 -1
- package/dist/react/{chunk-CUJDSH55.mjs → chunk-KTBOHRRE.mjs} +177 -148
- package/dist/react/index.cjs +110 -71
- package/dist/react/index.d.mts +69 -19
- package/dist/react/index.d.ts +69 -19
- package/dist/react/index.mjs +16 -6
- package/dist/react/{recall-FPPCKYYH.mjs → recall-DVX4W2UD.mjs} +1 -1
- package/dist/server/{chunk-UQDYBQVF.mjs → chunk-FKVYUOSD.mjs} +177 -148
- package/dist/server/index.cjs +110 -71
- package/dist/server/index.d.mts +69 -19
- package/dist/server/index.d.ts +69 -19
- package/dist/server/index.mjs +16 -6
- package/dist/server/{recall-ZHEPQNEU.mjs → recall-74L75BJ3.mjs} +1 -1
- package/package.json +1 -1
package/dist/expo/index.cjs
CHANGED
|
@@ -6401,11 +6401,11 @@ async function decomposeQuery(query, options) {
|
|
|
6401
6401
|
userMessage: `Classify the following memory query and decompose if composite. Respond with JSON only \u2014 do not answer the question, do not ask for clarification.
|
|
6402
6402
|
|
|
6403
6403
|
Query: ${trimmed}`,
|
|
6404
|
-
// Decompose runs
|
|
6404
|
+
// Decompose runs ahead of recall in the tool layer — tighter than the
|
|
6405
6405
|
// portalLlm default (consolidate/extract can wait longer).
|
|
6406
6406
|
timeoutMs: 2e4,
|
|
6407
6407
|
// No internal retry: a failure degrades to the safe `{specific,[query]}`
|
|
6408
|
-
// fallback below
|
|
6408
|
+
// fallback below. The agent/tool loop is the retry surface (719/B4).
|
|
6409
6409
|
maxAttempts: 1,
|
|
6410
6410
|
tag: "memory/decompose",
|
|
6411
6411
|
...options.fetchFn && { fetchFn: options.fetchFn }
|
|
@@ -6417,12 +6417,28 @@ Query: ${trimmed}`,
|
|
|
6417
6417
|
if (parsed === null) return fallback;
|
|
6418
6418
|
return validate(parsed, trimmed) ?? fallback;
|
|
6419
6419
|
}
|
|
6420
|
+
function normalizeSubQueries(raw) {
|
|
6421
|
+
if (!raw || raw.length === 0) return [];
|
|
6422
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6423
|
+
const out = [];
|
|
6424
|
+
for (const s of raw) {
|
|
6425
|
+
if (typeof s !== "string") continue;
|
|
6426
|
+
const t = s.trim();
|
|
6427
|
+
if (t.length === 0) continue;
|
|
6428
|
+
const key = t.toLowerCase();
|
|
6429
|
+
if (seen.has(key)) continue;
|
|
6430
|
+
seen.add(key);
|
|
6431
|
+
out.push(t);
|
|
6432
|
+
if (out.length >= MAX_SUB_QUERIES) break;
|
|
6433
|
+
}
|
|
6434
|
+
return out;
|
|
6435
|
+
}
|
|
6420
6436
|
function validate(parsed, originalQuery) {
|
|
6421
6437
|
if (typeof parsed !== "object" || parsed === null) return null;
|
|
6422
6438
|
const obj = parsed;
|
|
6423
6439
|
const mode = obj.mode === "composite" ? "composite" : "specific";
|
|
6424
6440
|
if (!Array.isArray(obj.subQueries)) return null;
|
|
6425
|
-
const subQueries = obj.subQueries
|
|
6441
|
+
const subQueries = normalizeSubQueries(obj.subQueries);
|
|
6426
6442
|
if (subQueries.length === 0) return null;
|
|
6427
6443
|
if (mode === "specific") {
|
|
6428
6444
|
return { mode: "specific", subQueries: [originalQuery] };
|
|
@@ -7039,12 +7055,12 @@ __export(recall_exports, {
|
|
|
7039
7055
|
function flagsForBudget(budget) {
|
|
7040
7056
|
switch (budget) {
|
|
7041
7057
|
case "high":
|
|
7042
|
-
return { rerank: true,
|
|
7058
|
+
return { rerank: true, traverse: true };
|
|
7043
7059
|
case "mid":
|
|
7044
|
-
return { rerank: true,
|
|
7060
|
+
return { rerank: true, traverse: false };
|
|
7045
7061
|
case "low":
|
|
7046
7062
|
default:
|
|
7047
|
-
return { rerank: false,
|
|
7063
|
+
return { rerank: false, traverse: false };
|
|
7048
7064
|
}
|
|
7049
7065
|
}
|
|
7050
7066
|
function dedupeBy(items, ...keys) {
|
|
@@ -7063,10 +7079,10 @@ function dedupeBy(items, ...keys) {
|
|
|
7063
7079
|
async function recall(query, ctx, options = {}) {
|
|
7064
7080
|
const types = options.types ?? ["fact"];
|
|
7065
7081
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
7066
|
-
const
|
|
7067
|
-
const flags = flagsForBudget(
|
|
7068
|
-
const
|
|
7069
|
-
const
|
|
7082
|
+
const usedBudget = options.budget ?? DEFAULT_BUDGET;
|
|
7083
|
+
const flags = flagsForBudget(usedBudget);
|
|
7084
|
+
const normalizedFacets = normalizeSubQueries(options.subQueries);
|
|
7085
|
+
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
7070
7086
|
const t0 = nowMs();
|
|
7071
7087
|
let prepMs = 0;
|
|
7072
7088
|
let factLaneMs = 0;
|
|
@@ -7087,7 +7103,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7087
7103
|
if (flags.rerank && factResults.length > 0 && hadV2Head && !didRerank) {
|
|
7088
7104
|
degraded.push("rerank-unavailable");
|
|
7089
7105
|
}
|
|
7090
|
-
if (
|
|
7106
|
+
if (usedBudget === "high" && options.decomposeOptions && !subQueries && !options.graphRefine) {
|
|
7107
|
+
degraded.push("decompose-moved");
|
|
7108
|
+
}
|
|
7091
7109
|
if (embeddingsUnavailable) degraded.push("embeddings-unavailable");
|
|
7092
7110
|
const diagnostics = {
|
|
7093
7111
|
usedBudget,
|
|
@@ -7200,10 +7218,8 @@ async function recall(query, ctx, options = {}) {
|
|
|
7200
7218
|
},
|
|
7201
7219
|
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
7202
7220
|
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
decomposeOptions: options.decomposeOptions
|
|
7206
|
-
},
|
|
7221
|
+
// 719/B4 — composite facets arrive pre-built; no LLM call here.
|
|
7222
|
+
...subQueries && { subQueries },
|
|
7207
7223
|
...options.scopes && { scopes: options.scopes },
|
|
7208
7224
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
7209
7225
|
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
@@ -7440,6 +7456,7 @@ var init_recall = __esm({
|
|
|
7440
7456
|
init_logger();
|
|
7441
7457
|
init_constants();
|
|
7442
7458
|
init_embeddings();
|
|
7459
|
+
init_decomposeQuery();
|
|
7443
7460
|
init_searchTool();
|
|
7444
7461
|
init_graphTraversal();
|
|
7445
7462
|
init_observationTrend();
|
|
@@ -8385,52 +8402,51 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
8385
8402
|
...searchOptions?.rrfK !== void 0 && { rrfK: searchOptions.rrfK },
|
|
8386
8403
|
...searchOptions?.factTypeWeights && { factTypeWeights: searchOptions.factTypeWeights }
|
|
8387
8404
|
};
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
}
|
|
8405
|
+
const normalizedFacets = normalizeSubQueries(searchOptions?.subQueries);
|
|
8406
|
+
const facetQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
8407
|
+
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
8408
|
+
let subEmbeddings;
|
|
8409
|
+
try {
|
|
8410
|
+
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
8411
|
+
} catch (err) {
|
|
8412
|
+
getLogger().warn(
|
|
8413
|
+
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
8414
|
+
);
|
|
8415
|
+
subEmbeddings = [];
|
|
8416
|
+
}
|
|
8417
|
+
const subEmbeddingsUsable = facetQueries.length > 0 && subEmbeddings.length === facetQueries.length && subEmbeddings.every((v) => v.length > 0 && v.length === queryEmbedding.length);
|
|
8418
|
+
if (subEmbeddings.length > 0 && !subEmbeddingsUsable) {
|
|
8419
|
+
getLogger().warn(
|
|
8420
|
+
`memoryVault: sub-query embedding returned ${subEmbeddings.length} vectors (dims ${subEmbeddings.map((v) => v.length).join(",")}) for ${facetQueries.length} sub-queries against a ${queryEmbedding.length}-dim query \u2014 falling back to single-query ranking`
|
|
8421
|
+
);
|
|
8422
|
+
}
|
|
8423
|
+
if (subEmbeddingsUsable) {
|
|
8424
|
+
const subQueries = facetQueries.map((sq, i) => ({
|
|
8425
|
+
query: sq,
|
|
8426
|
+
embedding: subEmbeddings[i]
|
|
8427
|
+
}));
|
|
8428
|
+
const v2HeadStats = { hadResults: false };
|
|
8429
|
+
const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
|
|
8430
|
+
limit,
|
|
8431
|
+
minSimilarity,
|
|
8432
|
+
rerank: !!searchOptions?.rerank,
|
|
8433
|
+
...searchOptions?.rerankTopN !== void 0 && {
|
|
8434
|
+
rerankTopN: searchOptions.rerankTopN
|
|
8435
|
+
},
|
|
8436
|
+
...searchOptions?.ceWeight !== void 0 && { ceWeight: searchOptions.ceWeight },
|
|
8437
|
+
...searchOptions?.mmr !== void 0 && { mmr: searchOptions.mmr },
|
|
8438
|
+
...tuning,
|
|
8439
|
+
...searchOptions?.entityRanking && { entityRanking: searchOptions.entityRanking },
|
|
8440
|
+
...searchOptions?.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
|
|
8441
|
+
rerankStats,
|
|
8442
|
+
v2HeadStats
|
|
8443
|
+
});
|
|
8444
|
+
return stampTimestamps({
|
|
8445
|
+
results: composite,
|
|
8446
|
+
vaultSize,
|
|
8447
|
+
reranked: rerankStats.applied,
|
|
8448
|
+
hadV2Head: v2HeadStats.hadResults
|
|
8449
|
+
});
|
|
8434
8450
|
}
|
|
8435
8451
|
}
|
|
8436
8452
|
if (useFusion && searchOptions?.rerank) {
|
|
@@ -8490,6 +8506,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
8490
8506
|
rankedOnCosine: false
|
|
8491
8507
|
};
|
|
8492
8508
|
}
|
|
8509
|
+
if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
|
|
8510
|
+
warnedProgrammaticDecomposeIgnored = true;
|
|
8511
|
+
getLogger().warn(
|
|
8512
|
+
'memoryVault: decompose:"llm" is ignored by searchVaultMemories \u2014 pass subQueries or use createMemoryVaultSearchTool / createRecallTool (719/B4)'
|
|
8513
|
+
);
|
|
8514
|
+
}
|
|
8493
8515
|
const prepared = await prepareVaultCandidates(
|
|
8494
8516
|
query,
|
|
8495
8517
|
vaultCtx,
|
|
@@ -8594,7 +8616,8 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
8594
8616
|
return "Error: A search query is required.";
|
|
8595
8617
|
}
|
|
8596
8618
|
try {
|
|
8597
|
-
const
|
|
8619
|
+
const wantsDecompose = searchOptions?.decompose === "llm" && !!searchOptions.decomposeOptions;
|
|
8620
|
+
const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
|
|
8598
8621
|
const folderId = searchOptions?.folderId ?? argFolderId;
|
|
8599
8622
|
if (searchOptions?.useFusion === false) {
|
|
8600
8623
|
const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
|
|
@@ -8618,6 +8641,13 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
8618
8641
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
8619
8642
|
);
|
|
8620
8643
|
}
|
|
8644
|
+
let subQueries;
|
|
8645
|
+
if (wantsDecompose && searchOptions?.decomposeOptions) {
|
|
8646
|
+
const decomp = await decomposeQuery(query, searchOptions.decomposeOptions);
|
|
8647
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
8648
|
+
subQueries = decomp.subQueries;
|
|
8649
|
+
}
|
|
8650
|
+
}
|
|
8621
8651
|
const { recall: recall2 } = await Promise.resolve().then(() => (init_recall(), recall_exports));
|
|
8622
8652
|
let recallDegraded = [];
|
|
8623
8653
|
const result = await recall2(
|
|
@@ -8634,9 +8664,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
8634
8664
|
...tuningForward,
|
|
8635
8665
|
...folderId !== void 0 && { folderId },
|
|
8636
8666
|
...searchOptions?.scopes && { scopes: searchOptions.scopes },
|
|
8637
|
-
...
|
|
8638
|
-
decomposeOptions: searchOptions.decomposeOptions
|
|
8639
|
-
}
|
|
8667
|
+
...subQueries && { subQueries }
|
|
8640
8668
|
}
|
|
8641
8669
|
);
|
|
8642
8670
|
if (result.vaultSize === 0) {
|
|
@@ -8666,7 +8694,7 @@ ${formatted}`;
|
|
|
8666
8694
|
}
|
|
8667
8695
|
};
|
|
8668
8696
|
}
|
|
8669
|
-
var SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
8697
|
+
var warnedProgrammaticDecomposeIgnored, SUPERSESSION_SIMILARITY_THRESHOLD, SUPERSESSION_MIN_AGE_GAP_MS, SUPERSESSION_BOOST_FACTOR, SUPERSESSION_MAX_WINDOW, EMBEDDINGS_DEGRADED_EMPTY_NO_LEXICAL;
|
|
8670
8698
|
var init_searchTool = __esm({
|
|
8671
8699
|
"src/lib/memoryVault/searchTool.ts"() {
|
|
8672
8700
|
"use strict";
|
|
@@ -8684,6 +8712,7 @@ var init_searchTool = __esm({
|
|
|
8684
8712
|
init_bm25();
|
|
8685
8713
|
init_decomposeQuery();
|
|
8686
8714
|
init_lruCache();
|
|
8715
|
+
warnedProgrammaticDecomposeIgnored = false;
|
|
8687
8716
|
SUPERSESSION_SIMILARITY_THRESHOLD = 0.7;
|
|
8688
8717
|
SUPERSESSION_MIN_AGE_GAP_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
8689
8718
|
SUPERSESSION_BOOST_FACTOR = 0.8;
|
|
@@ -16715,6 +16744,7 @@ function rankProfileCandidates(inputs, now = Date.now(), options = {}) {
|
|
|
16715
16744
|
init_recall();
|
|
16716
16745
|
|
|
16717
16746
|
// src/lib/memory/recallTool.ts
|
|
16747
|
+
init_decomposeQuery();
|
|
16718
16748
|
init_recall();
|
|
16719
16749
|
init_recallConstants();
|
|
16720
16750
|
var DEFAULT_LIMIT2 = 8;
|
|
@@ -16812,7 +16842,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
16812
16842
|
type: "function",
|
|
16813
16843
|
function: {
|
|
16814
16844
|
name: RECALL_TOOL_NAME,
|
|
16815
|
-
description:
|
|
16845
|
+
description: `Search the user's memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an \`id\` you can reference; conversation excerpts carry a date and role. Use this whenever the user's question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what's my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself.`,
|
|
16816
16846
|
arguments: {
|
|
16817
16847
|
type: "object",
|
|
16818
16848
|
properties: {
|
|
@@ -16867,6 +16897,13 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
16867
16897
|
let surfaced = 0;
|
|
16868
16898
|
try {
|
|
16869
16899
|
let recallDegraded = [];
|
|
16900
|
+
let subQueries;
|
|
16901
|
+
if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
|
|
16902
|
+
const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
|
|
16903
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
16904
|
+
subQueries = decomp.subQueries;
|
|
16905
|
+
}
|
|
16906
|
+
}
|
|
16870
16907
|
const recallOpts = {
|
|
16871
16908
|
onDiagnostics: (d) => {
|
|
16872
16909
|
recallDegraded = d.degraded;
|
|
@@ -16880,10 +16917,12 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
16880
16917
|
...toolOptions?.excludeConversationId && {
|
|
16881
16918
|
excludeConversationId: toolOptions.excludeConversationId
|
|
16882
16919
|
},
|
|
16883
|
-
|
|
16884
|
-
|
|
16885
|
-
|
|
16886
|
-
|
|
16920
|
+
// Do NOT forward decomposeOptions into recall() — rewrite already
|
|
16921
|
+
// ran above, and forwarding would falsely trip `decompose-moved`
|
|
16922
|
+
// on every specific-mode high-budget call. graphRefine auth can
|
|
16923
|
+
// be threaded later when the tool opts into that path.
|
|
16924
|
+
...toolOptions?.now !== void 0 && { now: toolOptions.now },
|
|
16925
|
+
...subQueries && { subQueries }
|
|
16887
16926
|
};
|
|
16888
16927
|
const result = await recall(query, ctx, recallOpts);
|
|
16889
16928
|
if (callbacks?.onChunksRetrieved) {
|
package/dist/expo/index.d.mts
CHANGED
|
@@ -5009,15 +5009,26 @@ interface MemoryVaultSearchOptions {
|
|
|
5009
5009
|
/** RRF smoothing constant for lane fusion. Default 60. */
|
|
5010
5010
|
rrfK?: number;
|
|
5011
5011
|
/**
|
|
5012
|
-
*
|
|
5013
|
-
*
|
|
5014
|
-
*
|
|
5015
|
-
*
|
|
5012
|
+
* Pre-decomposed facet queries for the composite ranker (719/B4). When
|
|
5013
|
+
* ≥2 are supplied (and embeddings are available), runs {@link rankComposite}
|
|
5014
|
+
* over them — no LLM call inside the search path. Callers that want LLM
|
|
5015
|
+
* rewrite (e.g. `createRecallTool`) call `decomposeQuery` first and pass
|
|
5016
|
+
* the facets here.
|
|
5017
|
+
*/
|
|
5018
|
+
subQueries?: string[];
|
|
5019
|
+
/**
|
|
5020
|
+
* @deprecated 719/B4 — ignored by {@link searchVaultMemories} /
|
|
5021
|
+
* {@link searchVaultMemoriesWithSize}. Pass {@link MemoryVaultSearchOptions.subQueries}
|
|
5022
|
+
* (or use `createRecallTool`). The legacy {@link createMemoryVaultSearchTool}
|
|
5023
|
+
* executor still honors `decompose: "llm"` + `decomposeOptions` for eval
|
|
5024
|
+
* parity, then forwards facets into the LLM-free search path.
|
|
5016
5025
|
*/
|
|
5017
5026
|
decompose?: "off" | "llm";
|
|
5018
|
-
/**
|
|
5019
|
-
*
|
|
5020
|
-
*
|
|
5027
|
+
/**
|
|
5028
|
+
* @deprecated 719/B4 — see `decompose`. Ignored on the programmatic search
|
|
5029
|
+
* path; tool-layer rewrite still reads this from the search-tool options.
|
|
5030
|
+
* Prefer `RecallToolOptions.decomposeOptions` with `createRecallTool`.
|
|
5031
|
+
*/
|
|
5021
5032
|
decomposeOptions?: PortalLlmAuth & {
|
|
5022
5033
|
baseUrl?: string;
|
|
5023
5034
|
model?: string;
|
|
@@ -5182,9 +5193,11 @@ type MemoryKind = "fact" | "chunk";
|
|
|
5182
5193
|
* Budget controls retrieval depth/cost. Higher budgets enable more
|
|
5183
5194
|
* candidate sources and the cross-encoder reranker.
|
|
5184
5195
|
*
|
|
5185
|
-
* - `low`: cosine + BM25
|
|
5186
|
-
* - `mid`: +
|
|
5187
|
-
* - `high`: +
|
|
5196
|
+
* - `low`: cosine + BM25 + recency. No reranker. Mobile default.
|
|
5197
|
+
* - `mid`: + cross-encoder rerank.
|
|
5198
|
+
* - `high`: + multi-hop graph traversal. LLM-free — query decomposition
|
|
5199
|
+
* (when wanted) lives in the tool/agent layer ({@link createRecallTool}),
|
|
5200
|
+
* not inside `recall()` itself (719/B4).
|
|
5188
5201
|
*/
|
|
5189
5202
|
type Budget = "low" | "mid" | "high";
|
|
5190
5203
|
interface ScoreBreakdown {
|
|
@@ -5284,10 +5297,28 @@ interface RecallOptions {
|
|
|
5284
5297
|
/** Drop results below this score. Default: 0.1 for facts, 0.5 for chunks (mirrors today's defaults). */
|
|
5285
5298
|
minScore?: number;
|
|
5286
5299
|
/**
|
|
5287
|
-
*
|
|
5288
|
-
*
|
|
5289
|
-
*
|
|
5290
|
-
*
|
|
5300
|
+
* Pre-decomposed facet queries for the composite ranker. When ≥2 are
|
|
5301
|
+
* supplied, the vault lane runs `rankComposite` over them (no LLM call
|
|
5302
|
+
* inside `recall()` — 719/B4). Callers that still want LLM rewrite
|
|
5303
|
+
* (e.g. {@link createRecallTool} at `budget: 'high'`) call
|
|
5304
|
+
* `decomposeQuery` themselves and pass the result here. A single entry
|
|
5305
|
+
* (or omitting this) keeps the single-query path.
|
|
5306
|
+
*/
|
|
5307
|
+
subQueries?: string[];
|
|
5308
|
+
/**
|
|
5309
|
+
* Auth + endpoint for optional LLM helpers that reuse portal auth —
|
|
5310
|
+
* currently {@link RecallOptions.graphRefine} neighbor selection.
|
|
5311
|
+
* Query decomposition is **not** driven by this field inside `recall()`
|
|
5312
|
+
* (719/B4); {@link createRecallTool} reads the same shape from
|
|
5313
|
+
* `RecallToolOptions.decomposeOptions` for tool-layer rewrite.
|
|
5314
|
+
*
|
|
5315
|
+
* Callers that still pass `{ budget: 'high', decomposeOptions }` without
|
|
5316
|
+
* {@link RecallOptions.subQueries} keep compiling but no longer rewrite —
|
|
5317
|
+
* `recall()` emits `decompose-moved` on {@link RecallDiagnostics.degraded}
|
|
5318
|
+
* so upgrades without a changelog read still leave a telemetry breadcrumb.
|
|
5319
|
+
*
|
|
5320
|
+
* Auth is the dual pattern — one of `apiKey` / `getToken` is required;
|
|
5321
|
+
* see {@link PortalLlmAuth}.
|
|
5291
5322
|
*/
|
|
5292
5323
|
decomposeOptions?: PortalLlmAuth & {
|
|
5293
5324
|
baseUrl?: string;
|
|
@@ -5391,9 +5422,22 @@ type RecallDegradation =
|
|
|
5391
5422
|
/** Rerank was requested (budget mid/high) but the cross-encoder didn't run
|
|
5392
5423
|
* this call — unavailable (e.g. React Native) or a transient failure. */
|
|
5393
5424
|
"rerank-unavailable"
|
|
5394
|
-
/**
|
|
5395
|
-
*
|
|
5425
|
+
/**
|
|
5426
|
+
* @deprecated 719/B4 moved query decomposition out of `recall()`. Budget
|
|
5427
|
+
* `high` no longer requires `decomposeOptions` and this signal is never
|
|
5428
|
+
* emitted. Prefer `"decompose-moved"` for the upgrade breadcrumb. Kept in
|
|
5429
|
+
* the union so existing telemetry consumers stay typed.
|
|
5430
|
+
*/
|
|
5396
5431
|
| "decompose-unavailable"
|
|
5432
|
+
/**
|
|
5433
|
+
* `budget: 'high'` with `decomposeOptions` set but no usable
|
|
5434
|
+
* {@link RecallOptions.subQueries}. Pre-B4 this call shape triggered LLM
|
|
5435
|
+
* rewrite inside `recall()`; post-B4 it stays on the single-query high
|
|
5436
|
+
* path (rerank + graph) and callers must pass facets (or use
|
|
5437
|
+
* {@link createRecallTool}). Surfaced so silent quality regressions show
|
|
5438
|
+
* up in diagnostics instead of looking healthier than before.
|
|
5439
|
+
*/
|
|
5440
|
+
| "decompose-moved"
|
|
5397
5441
|
/** There was no usable cosine lane, so results were ranked on BM25 (lexical)
|
|
5398
5442
|
* alone: either the query embedding failed (or came back empty), or no
|
|
5399
5443
|
* candidate had a vector to score against it because the row (re)embed failed.
|
|
@@ -7463,9 +7507,14 @@ declare function rankProfileCandidates(inputs: readonly ProfileSalienceInput[],
|
|
|
7463
7507
|
* Unified Recall API — single retrieval surface above vault + engine.
|
|
7464
7508
|
*
|
|
7465
7509
|
* Budget maps to pipeline depth (mirrors Hindsight's tiered defaults):
|
|
7466
|
-
* - `low` → V2 cosine + BM25 + recency (no rerank
|
|
7510
|
+
* - `low` → V2 cosine + BM25 + recency (no rerank)
|
|
7467
7511
|
* - `mid` → V2 + cross-encoder rerank
|
|
7468
|
-
* - `high` → V2 + rerank +
|
|
7512
|
+
* - `high` → V2 + rerank + multi-hop graph traversal
|
|
7513
|
+
*
|
|
7514
|
+
* LLM-free by design (719/B4): query decomposition for composite asks
|
|
7515
|
+
* lives in the tool/agent layer (`createRecallTool`), which may pass
|
|
7516
|
+
* pre-built `subQueries` into this API. `recall()` itself never pays an
|
|
7517
|
+
* LLM RTT.
|
|
7469
7518
|
*
|
|
7470
7519
|
* Fact + chunk lanes are fused with RRF (k=60). The previous naive
|
|
7471
7520
|
* "sort the union by raw score" path is gone — score scales differ
|
|
@@ -7520,7 +7569,8 @@ interface RecallToolOptions {
|
|
|
7520
7569
|
folderId?: string | null;
|
|
7521
7570
|
/** Exclude one conversation from chunk results (typically the active one). */
|
|
7522
7571
|
excludeConversationId?: string;
|
|
7523
|
-
/** LLM-decompose options; only used at budget="high".
|
|
7572
|
+
/** LLM-decompose options; only used at budget="high". Runs in THIS tool
|
|
7573
|
+
* executor (719/B4) — `recall()` itself is LLM-free. Auth follows the
|
|
7524
7574
|
* dual pattern: apiKey (server/CLI) or getToken (browser identity
|
|
7525
7575
|
* tokens) — at least one required. */
|
|
7526
7576
|
decomposeOptions?: PortalLlmAuth & {
|
package/dist/expo/index.d.ts
CHANGED
|
@@ -5009,15 +5009,26 @@ interface MemoryVaultSearchOptions {
|
|
|
5009
5009
|
/** RRF smoothing constant for lane fusion. Default 60. */
|
|
5010
5010
|
rrfK?: number;
|
|
5011
5011
|
/**
|
|
5012
|
-
*
|
|
5013
|
-
*
|
|
5014
|
-
*
|
|
5015
|
-
*
|
|
5012
|
+
* Pre-decomposed facet queries for the composite ranker (719/B4). When
|
|
5013
|
+
* ≥2 are supplied (and embeddings are available), runs {@link rankComposite}
|
|
5014
|
+
* over them — no LLM call inside the search path. Callers that want LLM
|
|
5015
|
+
* rewrite (e.g. `createRecallTool`) call `decomposeQuery` first and pass
|
|
5016
|
+
* the facets here.
|
|
5017
|
+
*/
|
|
5018
|
+
subQueries?: string[];
|
|
5019
|
+
/**
|
|
5020
|
+
* @deprecated 719/B4 — ignored by {@link searchVaultMemories} /
|
|
5021
|
+
* {@link searchVaultMemoriesWithSize}. Pass {@link MemoryVaultSearchOptions.subQueries}
|
|
5022
|
+
* (or use `createRecallTool`). The legacy {@link createMemoryVaultSearchTool}
|
|
5023
|
+
* executor still honors `decompose: "llm"` + `decomposeOptions` for eval
|
|
5024
|
+
* parity, then forwards facets into the LLM-free search path.
|
|
5016
5025
|
*/
|
|
5017
5026
|
decompose?: "off" | "llm";
|
|
5018
|
-
/**
|
|
5019
|
-
*
|
|
5020
|
-
*
|
|
5027
|
+
/**
|
|
5028
|
+
* @deprecated 719/B4 — see `decompose`. Ignored on the programmatic search
|
|
5029
|
+
* path; tool-layer rewrite still reads this from the search-tool options.
|
|
5030
|
+
* Prefer `RecallToolOptions.decomposeOptions` with `createRecallTool`.
|
|
5031
|
+
*/
|
|
5021
5032
|
decomposeOptions?: PortalLlmAuth & {
|
|
5022
5033
|
baseUrl?: string;
|
|
5023
5034
|
model?: string;
|
|
@@ -5182,9 +5193,11 @@ type MemoryKind = "fact" | "chunk";
|
|
|
5182
5193
|
* Budget controls retrieval depth/cost. Higher budgets enable more
|
|
5183
5194
|
* candidate sources and the cross-encoder reranker.
|
|
5184
5195
|
*
|
|
5185
|
-
* - `low`: cosine + BM25
|
|
5186
|
-
* - `mid`: +
|
|
5187
|
-
* - `high`: +
|
|
5196
|
+
* - `low`: cosine + BM25 + recency. No reranker. Mobile default.
|
|
5197
|
+
* - `mid`: + cross-encoder rerank.
|
|
5198
|
+
* - `high`: + multi-hop graph traversal. LLM-free — query decomposition
|
|
5199
|
+
* (when wanted) lives in the tool/agent layer ({@link createRecallTool}),
|
|
5200
|
+
* not inside `recall()` itself (719/B4).
|
|
5188
5201
|
*/
|
|
5189
5202
|
type Budget = "low" | "mid" | "high";
|
|
5190
5203
|
interface ScoreBreakdown {
|
|
@@ -5284,10 +5297,28 @@ interface RecallOptions {
|
|
|
5284
5297
|
/** Drop results below this score. Default: 0.1 for facts, 0.5 for chunks (mirrors today's defaults). */
|
|
5285
5298
|
minScore?: number;
|
|
5286
5299
|
/**
|
|
5287
|
-
*
|
|
5288
|
-
*
|
|
5289
|
-
*
|
|
5290
|
-
*
|
|
5300
|
+
* Pre-decomposed facet queries for the composite ranker. When ≥2 are
|
|
5301
|
+
* supplied, the vault lane runs `rankComposite` over them (no LLM call
|
|
5302
|
+
* inside `recall()` — 719/B4). Callers that still want LLM rewrite
|
|
5303
|
+
* (e.g. {@link createRecallTool} at `budget: 'high'`) call
|
|
5304
|
+
* `decomposeQuery` themselves and pass the result here. A single entry
|
|
5305
|
+
* (or omitting this) keeps the single-query path.
|
|
5306
|
+
*/
|
|
5307
|
+
subQueries?: string[];
|
|
5308
|
+
/**
|
|
5309
|
+
* Auth + endpoint for optional LLM helpers that reuse portal auth —
|
|
5310
|
+
* currently {@link RecallOptions.graphRefine} neighbor selection.
|
|
5311
|
+
* Query decomposition is **not** driven by this field inside `recall()`
|
|
5312
|
+
* (719/B4); {@link createRecallTool} reads the same shape from
|
|
5313
|
+
* `RecallToolOptions.decomposeOptions` for tool-layer rewrite.
|
|
5314
|
+
*
|
|
5315
|
+
* Callers that still pass `{ budget: 'high', decomposeOptions }` without
|
|
5316
|
+
* {@link RecallOptions.subQueries} keep compiling but no longer rewrite —
|
|
5317
|
+
* `recall()` emits `decompose-moved` on {@link RecallDiagnostics.degraded}
|
|
5318
|
+
* so upgrades without a changelog read still leave a telemetry breadcrumb.
|
|
5319
|
+
*
|
|
5320
|
+
* Auth is the dual pattern — one of `apiKey` / `getToken` is required;
|
|
5321
|
+
* see {@link PortalLlmAuth}.
|
|
5291
5322
|
*/
|
|
5292
5323
|
decomposeOptions?: PortalLlmAuth & {
|
|
5293
5324
|
baseUrl?: string;
|
|
@@ -5391,9 +5422,22 @@ type RecallDegradation =
|
|
|
5391
5422
|
/** Rerank was requested (budget mid/high) but the cross-encoder didn't run
|
|
5392
5423
|
* this call — unavailable (e.g. React Native) or a transient failure. */
|
|
5393
5424
|
"rerank-unavailable"
|
|
5394
|
-
/**
|
|
5395
|
-
*
|
|
5425
|
+
/**
|
|
5426
|
+
* @deprecated 719/B4 moved query decomposition out of `recall()`. Budget
|
|
5427
|
+
* `high` no longer requires `decomposeOptions` and this signal is never
|
|
5428
|
+
* emitted. Prefer `"decompose-moved"` for the upgrade breadcrumb. Kept in
|
|
5429
|
+
* the union so existing telemetry consumers stay typed.
|
|
5430
|
+
*/
|
|
5396
5431
|
| "decompose-unavailable"
|
|
5432
|
+
/**
|
|
5433
|
+
* `budget: 'high'` with `decomposeOptions` set but no usable
|
|
5434
|
+
* {@link RecallOptions.subQueries}. Pre-B4 this call shape triggered LLM
|
|
5435
|
+
* rewrite inside `recall()`; post-B4 it stays on the single-query high
|
|
5436
|
+
* path (rerank + graph) and callers must pass facets (or use
|
|
5437
|
+
* {@link createRecallTool}). Surfaced so silent quality regressions show
|
|
5438
|
+
* up in diagnostics instead of looking healthier than before.
|
|
5439
|
+
*/
|
|
5440
|
+
| "decompose-moved"
|
|
5397
5441
|
/** There was no usable cosine lane, so results were ranked on BM25 (lexical)
|
|
5398
5442
|
* alone: either the query embedding failed (or came back empty), or no
|
|
5399
5443
|
* candidate had a vector to score against it because the row (re)embed failed.
|
|
@@ -7463,9 +7507,14 @@ declare function rankProfileCandidates(inputs: readonly ProfileSalienceInput[],
|
|
|
7463
7507
|
* Unified Recall API — single retrieval surface above vault + engine.
|
|
7464
7508
|
*
|
|
7465
7509
|
* Budget maps to pipeline depth (mirrors Hindsight's tiered defaults):
|
|
7466
|
-
* - `low` → V2 cosine + BM25 + recency (no rerank
|
|
7510
|
+
* - `low` → V2 cosine + BM25 + recency (no rerank)
|
|
7467
7511
|
* - `mid` → V2 + cross-encoder rerank
|
|
7468
|
-
* - `high` → V2 + rerank +
|
|
7512
|
+
* - `high` → V2 + rerank + multi-hop graph traversal
|
|
7513
|
+
*
|
|
7514
|
+
* LLM-free by design (719/B4): query decomposition for composite asks
|
|
7515
|
+
* lives in the tool/agent layer (`createRecallTool`), which may pass
|
|
7516
|
+
* pre-built `subQueries` into this API. `recall()` itself never pays an
|
|
7517
|
+
* LLM RTT.
|
|
7469
7518
|
*
|
|
7470
7519
|
* Fact + chunk lanes are fused with RRF (k=60). The previous naive
|
|
7471
7520
|
* "sort the union by raw score" path is gone — score scales differ
|
|
@@ -7520,7 +7569,8 @@ interface RecallToolOptions {
|
|
|
7520
7569
|
folderId?: string | null;
|
|
7521
7570
|
/** Exclude one conversation from chunk results (typically the active one). */
|
|
7522
7571
|
excludeConversationId?: string;
|
|
7523
|
-
/** LLM-decompose options; only used at budget="high".
|
|
7572
|
+
/** LLM-decompose options; only used at budget="high". Runs in THIS tool
|
|
7573
|
+
* executor (719/B4) — `recall()` itself is LLM-free. Auth follows the
|
|
7524
7574
|
* dual pattern: apiKey (server/CLI) or getToken (browser identity
|
|
7525
7575
|
* tokens) — at least one required. */
|
|
7526
7576
|
decomposeOptions?: PortalLlmAuth & {
|
package/dist/expo/index.mjs
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
createVaultEmbeddingCache,
|
|
43
43
|
createVaultMemoriesBatchOp,
|
|
44
44
|
createVaultMemoryOp,
|
|
45
|
+
decomposeQuery,
|
|
45
46
|
decryptField,
|
|
46
47
|
decryptJsonField,
|
|
47
48
|
deleteAllVaultMemoriesForUserOp,
|
|
@@ -119,7 +120,7 @@ import {
|
|
|
119
120
|
upsertMessageOp,
|
|
120
121
|
useEncryption,
|
|
121
122
|
vaultMemoryToStored
|
|
122
|
-
} from "./chunk-
|
|
123
|
+
} from "./chunk-SIMGZQ4P.mjs";
|
|
123
124
|
import {
|
|
124
125
|
PII_PATTERNS,
|
|
125
126
|
PiiRedactor,
|
|
@@ -7814,7 +7815,7 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
7814
7815
|
type: "function",
|
|
7815
7816
|
function: {
|
|
7816
7817
|
name: RECALL_TOOL_NAME,
|
|
7817
|
-
description:
|
|
7818
|
+
description: `Search the user's memory across stored facts/preferences and past conversation excerpts. Returns a unified ranked list \u2014 facts carry an \`id\` you can reference; conversation excerpts carry a date and role. Use this whenever the user's question may relate to anything previously discussed or saved (preferences, prior decisions, past topics). Phrase the query naturally. For multi-faceted / overview questions ("tell me about the user", "what's my tech stack"), prefer several targeted searches \u2014 one facet each (e.g. name, work, hobbies) \u2014 over a single broad query; fuse the results yourself.`,
|
|
7818
7819
|
arguments: {
|
|
7819
7820
|
type: "object",
|
|
7820
7821
|
properties: {
|
|
@@ -7869,6 +7870,13 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
7869
7870
|
let surfaced = 0;
|
|
7870
7871
|
try {
|
|
7871
7872
|
let recallDegraded = [];
|
|
7873
|
+
let subQueries;
|
|
7874
|
+
if (defaultBudget === "high" && toolOptions?.decomposeOptions) {
|
|
7875
|
+
const decomp = await decomposeQuery(query, toolOptions.decomposeOptions);
|
|
7876
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
7877
|
+
subQueries = decomp.subQueries;
|
|
7878
|
+
}
|
|
7879
|
+
}
|
|
7872
7880
|
const recallOpts = {
|
|
7873
7881
|
onDiagnostics: (d) => {
|
|
7874
7882
|
recallDegraded = d.degraded;
|
|
@@ -7882,10 +7890,12 @@ function createRecallTool(ctx, toolOptions, callbacks) {
|
|
|
7882
7890
|
...toolOptions?.excludeConversationId && {
|
|
7883
7891
|
excludeConversationId: toolOptions.excludeConversationId
|
|
7884
7892
|
},
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7893
|
+
// Do NOT forward decomposeOptions into recall() — rewrite already
|
|
7894
|
+
// ran above, and forwarding would falsely trip `decompose-moved`
|
|
7895
|
+
// on every specific-mode high-budget call. graphRefine auth can
|
|
7896
|
+
// be threaded later when the tool opts into that path.
|
|
7897
|
+
...toolOptions?.now !== void 0 && { now: toolOptions.now },
|
|
7898
|
+
...subQueries && { subQueries }
|
|
7889
7899
|
};
|
|
7890
7900
|
const result = await recall(query, ctx, recallOpts);
|
|
7891
7901
|
if (callbacks?.onChunksRetrieved) {
|