@anuma/sdk 4.2.1 → 5.0.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.
- package/dist/expo/{chunk-3CDSIN22.mjs → chunk-SIMGZQ4P.mjs} +177 -148
- package/dist/expo/index.cjs +164 -73
- package/dist/expo/index.d.mts +75 -20
- package/dist/expo/index.d.ts +75 -20
- package/dist/expo/index.mjs +70 -8
- 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 +164 -73
- package/dist/react/index.d.mts +75 -20
- package/dist/react/index.d.ts +75 -20
- package/dist/react/index.mjs +70 -8
- 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 +164 -73
- package/dist/server/index.d.mts +75 -20
- package/dist/server/index.d.ts +75 -20
- package/dist/server/index.mjs +70 -8
- package/dist/server/{recall-ZHEPQNEU.mjs → recall-74L75BJ3.mjs} +1 -1
- package/package.json +1 -1
|
@@ -4748,6 +4748,107 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
4748
4748
|
return embeddedCount;
|
|
4749
4749
|
}
|
|
4750
4750
|
|
|
4751
|
+
// src/lib/memoryVault/decomposeQuery.ts
|
|
4752
|
+
var DEFAULT_MODEL = "inclusionai/ling-2.6-flash";
|
|
4753
|
+
var MAX_SUB_QUERIES = 5;
|
|
4754
|
+
var SYSTEM_PROMPT = `You classify a memory query and, if needed, decompose it into concrete sub-queries.
|
|
4755
|
+
|
|
4756
|
+
CLASSIFICATION RULES \u2014 be strict:
|
|
4757
|
+
- "specific": asks for one fact OR a list of items in ONE category (one dimension).
|
|
4758
|
+
Examples: a name, a date, a preference, a location, an ID, a value, "what hobbies",
|
|
4759
|
+
"which conferences", "what open source projects", "what does X do for exercise".
|
|
4760
|
+
Even when the answer is a list, if all items belong to one dimension, it is specific.
|
|
4761
|
+
- "composite": asks about a person, system, or setup MULTI-DIMENSIONALLY \u2014 a summary,
|
|
4762
|
+
an overview, a profile, "tell me about X", "what is my X setup", "describe the team's
|
|
4763
|
+
X". The answer must span multiple distinct fact dimensions (e.g. for a "tech stack":
|
|
4764
|
+
language + database + framework + tools \u2014 four different dimensions).
|
|
4765
|
+
|
|
4766
|
+
When in doubt, prefer "specific". Mis-classifying a single-dimension list as composite
|
|
4767
|
+
hurts retrieval more than the reverse.
|
|
4768
|
+
|
|
4769
|
+
SUB-QUERY RULES (composite only, 3\u20135 questions):
|
|
4770
|
+
- Each sub-query targets a DIFFERENT fact dimension.
|
|
4771
|
+
- Use SHORT parenthetical examples \u2014 2\u20134 concrete options that anchor the
|
|
4772
|
+
embedding to likely memory content. Examples must be terms a user would
|
|
4773
|
+
actually have in their notes (e.g., "Postgres" not "PostgreSQL 15.2 with
|
|
4774
|
+
read replicas"). No verbose qualifiers like "and versions" or "and any
|
|
4775
|
+
relevant configuration details".
|
|
4776
|
+
- 8\u201314 words including the parenthetical. Like a human asking a follow-up.
|
|
4777
|
+
|
|
4778
|
+
Examples:
|
|
4779
|
+
"What is my dog's name?" \u2192 {"mode":"specific","subQueries":["What is my dog's name?"]}
|
|
4780
|
+
"What does the user do for exercise?" \u2192 {"mode":"specific","subQueries":["What does the user do for exercise?"]}
|
|
4781
|
+
"What conferences has the user attended?" \u2192 {"mode":"specific","subQueries":["What conferences has the user attended?"]}
|
|
4782
|
+
"What did I do last Tuesday?" \u2192 {"mode":"specific","subQueries":["What did I do last Tuesday?"]}
|
|
4783
|
+
"Tell me about the user as a person" \u2192 {"mode":"composite","subQueries":["What is the user's name?","Where does the user live?","What does the user do for work?","Any health conditions or allergies?","What are the user's hobbies (sports, music, games)?"]}
|
|
4784
|
+
"What is the user's tech stack?" \u2192 {"mode":"composite","subQueries":["What programming languages does the user use (Python, Go, TypeScript)?","What database does the user use (Postgres, MySQL, Mongo)?","What framework or ORM (React, Django, Prisma)?","What infrastructure (AWS, Docker, K8s)?","What testing tools (Jest, pytest, Cypress)?"]}
|
|
4785
|
+
"Describe the user's development environment" \u2192 {"mode":"composite","subQueries":["What operating system does the user use (macOS, Linux, Windows)?","What editor or IDE (VS Code, Vim, IntelliJ)?","What shell or terminal setup (zsh, bash, tmux)?","What keyboard or display setup (mechanical, vertical monitor)?","Any UI preferences (dark mode, font, vim keybindings)?"]}
|
|
4786
|
+
|
|
4787
|
+
Output strict JSON. No prose.`;
|
|
4788
|
+
async function decomposeQuery(query, options) {
|
|
4789
|
+
const fallback = { mode: "specific", subQueries: [query] };
|
|
4790
|
+
const trimmed = query.trim();
|
|
4791
|
+
if (trimmed.length === 0) return fallback;
|
|
4792
|
+
let parsed;
|
|
4793
|
+
try {
|
|
4794
|
+
parsed = await callPortalJsonCompletion({
|
|
4795
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
4796
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
4797
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
4798
|
+
model: options.model ?? DEFAULT_MODEL,
|
|
4799
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
4800
|
+
// Wrap the bare query in a task framing so the model treats it as
|
|
4801
|
+
// input to classify, not as a question to answer conversationally.
|
|
4802
|
+
// Bare-query inputs caused Anthropic models to respond with prose
|
|
4803
|
+
// like "Do you mean...?" before this wrap.
|
|
4804
|
+
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.
|
|
4805
|
+
|
|
4806
|
+
Query: ${trimmed}`,
|
|
4807
|
+
// Decompose runs ahead of recall in the tool layer — tighter than the
|
|
4808
|
+
// portalLlm default (consolidate/extract can wait longer).
|
|
4809
|
+
timeoutMs: 2e4,
|
|
4810
|
+
// No internal retry: a failure degrades to the safe `{specific,[query]}`
|
|
4811
|
+
// fallback below. The agent/tool loop is the retry surface (719/B4).
|
|
4812
|
+
maxAttempts: 1,
|
|
4813
|
+
tag: "memory/decompose",
|
|
4814
|
+
...options.fetchFn && { fetchFn: options.fetchFn }
|
|
4815
|
+
});
|
|
4816
|
+
} catch (err) {
|
|
4817
|
+
getLogger().warn("memoryVault/decompose: portal call failed, falling back to specific", err);
|
|
4818
|
+
return fallback;
|
|
4819
|
+
}
|
|
4820
|
+
if (parsed === null) return fallback;
|
|
4821
|
+
return validate(parsed, trimmed) ?? fallback;
|
|
4822
|
+
}
|
|
4823
|
+
function normalizeSubQueries(raw) {
|
|
4824
|
+
if (!raw || raw.length === 0) return [];
|
|
4825
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4826
|
+
const out = [];
|
|
4827
|
+
for (const s of raw) {
|
|
4828
|
+
if (typeof s !== "string") continue;
|
|
4829
|
+
const t = s.trim();
|
|
4830
|
+
if (t.length === 0) continue;
|
|
4831
|
+
const key = t.toLowerCase();
|
|
4832
|
+
if (seen.has(key)) continue;
|
|
4833
|
+
seen.add(key);
|
|
4834
|
+
out.push(t);
|
|
4835
|
+
if (out.length >= MAX_SUB_QUERIES) break;
|
|
4836
|
+
}
|
|
4837
|
+
return out;
|
|
4838
|
+
}
|
|
4839
|
+
function validate(parsed, originalQuery) {
|
|
4840
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
4841
|
+
const obj = parsed;
|
|
4842
|
+
const mode = obj.mode === "composite" ? "composite" : "specific";
|
|
4843
|
+
if (!Array.isArray(obj.subQueries)) return null;
|
|
4844
|
+
const subQueries = normalizeSubQueries(obj.subQueries);
|
|
4845
|
+
if (subQueries.length === 0) return null;
|
|
4846
|
+
if (mode === "specific") {
|
|
4847
|
+
return { mode: "specific", subQueries: [originalQuery] };
|
|
4848
|
+
}
|
|
4849
|
+
return { mode, subQueries };
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4751
4852
|
// src/lib/memory/mmr.ts
|
|
4752
4853
|
function applyMMR(candidates, k, lambda = 0.5) {
|
|
4753
4854
|
if (candidates.length === 0 || k <= 0) return [];
|
|
@@ -5125,91 +5226,6 @@ function scoreBM25(query, items) {
|
|
|
5125
5226
|
return scoreBM25Prepared(query, prepareBM25Corpus(items));
|
|
5126
5227
|
}
|
|
5127
5228
|
|
|
5128
|
-
// src/lib/memoryVault/decomposeQuery.ts
|
|
5129
|
-
var DEFAULT_MODEL = "inclusionai/ling-2.6-flash";
|
|
5130
|
-
var MAX_SUB_QUERIES = 5;
|
|
5131
|
-
var SYSTEM_PROMPT = `You classify a memory query and, if needed, decompose it into concrete sub-queries.
|
|
5132
|
-
|
|
5133
|
-
CLASSIFICATION RULES \u2014 be strict:
|
|
5134
|
-
- "specific": asks for one fact OR a list of items in ONE category (one dimension).
|
|
5135
|
-
Examples: a name, a date, a preference, a location, an ID, a value, "what hobbies",
|
|
5136
|
-
"which conferences", "what open source projects", "what does X do for exercise".
|
|
5137
|
-
Even when the answer is a list, if all items belong to one dimension, it is specific.
|
|
5138
|
-
- "composite": asks about a person, system, or setup MULTI-DIMENSIONALLY \u2014 a summary,
|
|
5139
|
-
an overview, a profile, "tell me about X", "what is my X setup", "describe the team's
|
|
5140
|
-
X". The answer must span multiple distinct fact dimensions (e.g. for a "tech stack":
|
|
5141
|
-
language + database + framework + tools \u2014 four different dimensions).
|
|
5142
|
-
|
|
5143
|
-
When in doubt, prefer "specific". Mis-classifying a single-dimension list as composite
|
|
5144
|
-
hurts retrieval more than the reverse.
|
|
5145
|
-
|
|
5146
|
-
SUB-QUERY RULES (composite only, 3\u20135 questions):
|
|
5147
|
-
- Each sub-query targets a DIFFERENT fact dimension.
|
|
5148
|
-
- Use SHORT parenthetical examples \u2014 2\u20134 concrete options that anchor the
|
|
5149
|
-
embedding to likely memory content. Examples must be terms a user would
|
|
5150
|
-
actually have in their notes (e.g., "Postgres" not "PostgreSQL 15.2 with
|
|
5151
|
-
read replicas"). No verbose qualifiers like "and versions" or "and any
|
|
5152
|
-
relevant configuration details".
|
|
5153
|
-
- 8\u201314 words including the parenthetical. Like a human asking a follow-up.
|
|
5154
|
-
|
|
5155
|
-
Examples:
|
|
5156
|
-
"What is my dog's name?" \u2192 {"mode":"specific","subQueries":["What is my dog's name?"]}
|
|
5157
|
-
"What does the user do for exercise?" \u2192 {"mode":"specific","subQueries":["What does the user do for exercise?"]}
|
|
5158
|
-
"What conferences has the user attended?" \u2192 {"mode":"specific","subQueries":["What conferences has the user attended?"]}
|
|
5159
|
-
"What did I do last Tuesday?" \u2192 {"mode":"specific","subQueries":["What did I do last Tuesday?"]}
|
|
5160
|
-
"Tell me about the user as a person" \u2192 {"mode":"composite","subQueries":["What is the user's name?","Where does the user live?","What does the user do for work?","Any health conditions or allergies?","What are the user's hobbies (sports, music, games)?"]}
|
|
5161
|
-
"What is the user's tech stack?" \u2192 {"mode":"composite","subQueries":["What programming languages does the user use (Python, Go, TypeScript)?","What database does the user use (Postgres, MySQL, Mongo)?","What framework or ORM (React, Django, Prisma)?","What infrastructure (AWS, Docker, K8s)?","What testing tools (Jest, pytest, Cypress)?"]}
|
|
5162
|
-
"Describe the user's development environment" \u2192 {"mode":"composite","subQueries":["What operating system does the user use (macOS, Linux, Windows)?","What editor or IDE (VS Code, Vim, IntelliJ)?","What shell or terminal setup (zsh, bash, tmux)?","What keyboard or display setup (mechanical, vertical monitor)?","Any UI preferences (dark mode, font, vim keybindings)?"]}
|
|
5163
|
-
|
|
5164
|
-
Output strict JSON. No prose.`;
|
|
5165
|
-
async function decomposeQuery(query, options) {
|
|
5166
|
-
const fallback = { mode: "specific", subQueries: [query] };
|
|
5167
|
-
const trimmed = query.trim();
|
|
5168
|
-
if (trimmed.length === 0) return fallback;
|
|
5169
|
-
let parsed;
|
|
5170
|
-
try {
|
|
5171
|
-
parsed = await callPortalJsonCompletion({
|
|
5172
|
-
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
5173
|
-
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
5174
|
-
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
5175
|
-
model: options.model ?? DEFAULT_MODEL,
|
|
5176
|
-
systemPrompt: SYSTEM_PROMPT,
|
|
5177
|
-
// Wrap the bare query in a task framing so the model treats it as
|
|
5178
|
-
// input to classify, not as a question to answer conversationally.
|
|
5179
|
-
// Bare-query inputs caused Anthropic models to respond with prose
|
|
5180
|
-
// like "Do you mean...?" before this wrap.
|
|
5181
|
-
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.
|
|
5182
|
-
|
|
5183
|
-
Query: ${trimmed}`,
|
|
5184
|
-
// Decompose runs on the recall hot path — tighter than the
|
|
5185
|
-
// portalLlm default (consolidate/extract can wait longer).
|
|
5186
|
-
timeoutMs: 2e4,
|
|
5187
|
-
// No internal retry: a failure degrades to the safe `{specific,[query]}`
|
|
5188
|
-
// fallback below, so retrying would only add latency on the hot path.
|
|
5189
|
-
maxAttempts: 1,
|
|
5190
|
-
tag: "memory/decompose",
|
|
5191
|
-
...options.fetchFn && { fetchFn: options.fetchFn }
|
|
5192
|
-
});
|
|
5193
|
-
} catch (err) {
|
|
5194
|
-
getLogger().warn("memoryVault/decompose: portal call failed, falling back to specific", err);
|
|
5195
|
-
return fallback;
|
|
5196
|
-
}
|
|
5197
|
-
if (parsed === null) return fallback;
|
|
5198
|
-
return validate(parsed, trimmed) ?? fallback;
|
|
5199
|
-
}
|
|
5200
|
-
function validate(parsed, originalQuery) {
|
|
5201
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
5202
|
-
const obj = parsed;
|
|
5203
|
-
const mode = obj.mode === "composite" ? "composite" : "specific";
|
|
5204
|
-
if (!Array.isArray(obj.subQueries)) return null;
|
|
5205
|
-
const subQueries = obj.subQueries.filter((s) => typeof s === "string").map((s) => s.trim()).filter((s) => s.length > 0).slice(0, MAX_SUB_QUERIES);
|
|
5206
|
-
if (subQueries.length === 0) return null;
|
|
5207
|
-
if (mode === "specific") {
|
|
5208
|
-
return { mode: "specific", subQueries: [originalQuery] };
|
|
5209
|
-
}
|
|
5210
|
-
return { mode, subQueries };
|
|
5211
|
-
}
|
|
5212
|
-
|
|
5213
5229
|
// src/lib/memoryVault/lruCache.ts
|
|
5214
5230
|
var DEFAULT_VAULT_CACHE_SIZE = 5e3;
|
|
5215
5231
|
var LRUCache = class extends Map {
|
|
@@ -5243,6 +5259,7 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
5243
5259
|
}
|
|
5244
5260
|
|
|
5245
5261
|
// src/lib/memoryVault/searchTool.ts
|
|
5262
|
+
var warnedProgrammaticDecomposeIgnored = false;
|
|
5246
5263
|
function normalizeEventTimeKind(kind) {
|
|
5247
5264
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
5248
5265
|
}
|
|
@@ -6177,52 +6194,51 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
6177
6194
|
...searchOptions?.rrfK !== void 0 && { rrfK: searchOptions.rrfK },
|
|
6178
6195
|
...searchOptions?.factTypeWeights && { factTypeWeights: searchOptions.factTypeWeights }
|
|
6179
6196
|
};
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
}
|
|
6197
|
+
const normalizedFacets = normalizeSubQueries(searchOptions?.subQueries);
|
|
6198
|
+
const facetQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
6199
|
+
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
6200
|
+
let subEmbeddings;
|
|
6201
|
+
try {
|
|
6202
|
+
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
6203
|
+
} catch (err) {
|
|
6204
|
+
getLogger().warn(
|
|
6205
|
+
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
6206
|
+
);
|
|
6207
|
+
subEmbeddings = [];
|
|
6208
|
+
}
|
|
6209
|
+
const subEmbeddingsUsable = facetQueries.length > 0 && subEmbeddings.length === facetQueries.length && subEmbeddings.every((v) => v.length > 0 && v.length === queryEmbedding.length);
|
|
6210
|
+
if (subEmbeddings.length > 0 && !subEmbeddingsUsable) {
|
|
6211
|
+
getLogger().warn(
|
|
6212
|
+
`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`
|
|
6213
|
+
);
|
|
6214
|
+
}
|
|
6215
|
+
if (subEmbeddingsUsable) {
|
|
6216
|
+
const subQueries = facetQueries.map((sq, i) => ({
|
|
6217
|
+
query: sq,
|
|
6218
|
+
embedding: subEmbeddings[i]
|
|
6219
|
+
}));
|
|
6220
|
+
const v2HeadStats = { hadResults: false };
|
|
6221
|
+
const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
|
|
6222
|
+
limit,
|
|
6223
|
+
minSimilarity,
|
|
6224
|
+
rerank: !!searchOptions?.rerank,
|
|
6225
|
+
...searchOptions?.rerankTopN !== void 0 && {
|
|
6226
|
+
rerankTopN: searchOptions.rerankTopN
|
|
6227
|
+
},
|
|
6228
|
+
...searchOptions?.ceWeight !== void 0 && { ceWeight: searchOptions.ceWeight },
|
|
6229
|
+
...searchOptions?.mmr !== void 0 && { mmr: searchOptions.mmr },
|
|
6230
|
+
...tuning,
|
|
6231
|
+
...searchOptions?.entityRanking && { entityRanking: searchOptions.entityRanking },
|
|
6232
|
+
...searchOptions?.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
|
|
6233
|
+
rerankStats,
|
|
6234
|
+
v2HeadStats
|
|
6235
|
+
});
|
|
6236
|
+
return stampTimestamps({
|
|
6237
|
+
results: composite,
|
|
6238
|
+
vaultSize,
|
|
6239
|
+
reranked: rerankStats.applied,
|
|
6240
|
+
hadV2Head: v2HeadStats.hadResults
|
|
6241
|
+
});
|
|
6226
6242
|
}
|
|
6227
6243
|
}
|
|
6228
6244
|
if (useFusion && searchOptions?.rerank) {
|
|
@@ -6282,6 +6298,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
6282
6298
|
rankedOnCosine: false
|
|
6283
6299
|
};
|
|
6284
6300
|
}
|
|
6301
|
+
if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
|
|
6302
|
+
warnedProgrammaticDecomposeIgnored = true;
|
|
6303
|
+
getLogger().warn(
|
|
6304
|
+
'memoryVault: decompose:"llm" is ignored by searchVaultMemories \u2014 pass subQueries or use createMemoryVaultSearchTool / createRecallTool (719/B4)'
|
|
6305
|
+
);
|
|
6306
|
+
}
|
|
6285
6307
|
const prepared = await prepareVaultCandidates(
|
|
6286
6308
|
query,
|
|
6287
6309
|
vaultCtx,
|
|
@@ -6387,7 +6409,8 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6387
6409
|
return "Error: A search query is required.";
|
|
6388
6410
|
}
|
|
6389
6411
|
try {
|
|
6390
|
-
const
|
|
6412
|
+
const wantsDecompose = searchOptions?.decompose === "llm" && !!searchOptions.decomposeOptions;
|
|
6413
|
+
const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
|
|
6391
6414
|
const folderId = searchOptions?.folderId ?? argFolderId;
|
|
6392
6415
|
if (searchOptions?.useFusion === false) {
|
|
6393
6416
|
const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
|
|
@@ -6411,7 +6434,14 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6411
6434
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
6412
6435
|
);
|
|
6413
6436
|
}
|
|
6414
|
-
|
|
6437
|
+
let subQueries;
|
|
6438
|
+
if (wantsDecompose && searchOptions?.decomposeOptions) {
|
|
6439
|
+
const decomp = await decomposeQuery(query, searchOptions.decomposeOptions);
|
|
6440
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
6441
|
+
subQueries = decomp.subQueries;
|
|
6442
|
+
}
|
|
6443
|
+
}
|
|
6444
|
+
const { recall: recall2 } = await import("./recall-PIDYDFIQ.mjs");
|
|
6415
6445
|
let recallDegraded = [];
|
|
6416
6446
|
const result = await recall2(
|
|
6417
6447
|
query,
|
|
@@ -6427,9 +6457,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6427
6457
|
...tuningForward,
|
|
6428
6458
|
...folderId !== void 0 && { folderId },
|
|
6429
6459
|
...searchOptions?.scopes && { scopes: searchOptions.scopes },
|
|
6430
|
-
...
|
|
6431
|
-
decomposeOptions: searchOptions.decomposeOptions
|
|
6432
|
-
}
|
|
6460
|
+
...subQueries && { subQueries }
|
|
6433
6461
|
}
|
|
6434
6462
|
);
|
|
6435
6463
|
if (result.vaultSize === 0) {
|
|
@@ -6957,12 +6985,12 @@ var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
|
6957
6985
|
function flagsForBudget(budget) {
|
|
6958
6986
|
switch (budget) {
|
|
6959
6987
|
case "high":
|
|
6960
|
-
return { rerank: true,
|
|
6988
|
+
return { rerank: true, traverse: true };
|
|
6961
6989
|
case "mid":
|
|
6962
|
-
return { rerank: true,
|
|
6990
|
+
return { rerank: true, traverse: false };
|
|
6963
6991
|
case "low":
|
|
6964
6992
|
default:
|
|
6965
|
-
return { rerank: false,
|
|
6993
|
+
return { rerank: false, traverse: false };
|
|
6966
6994
|
}
|
|
6967
6995
|
}
|
|
6968
6996
|
function dedupeBy(items, ...keys) {
|
|
@@ -6981,10 +7009,10 @@ function dedupeBy(items, ...keys) {
|
|
|
6981
7009
|
async function recall(query, ctx, options = {}) {
|
|
6982
7010
|
const types = options.types ?? ["fact"];
|
|
6983
7011
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
6984
|
-
const
|
|
6985
|
-
const flags = flagsForBudget(
|
|
6986
|
-
const
|
|
6987
|
-
const
|
|
7012
|
+
const usedBudget = options.budget ?? DEFAULT_BUDGET;
|
|
7013
|
+
const flags = flagsForBudget(usedBudget);
|
|
7014
|
+
const normalizedFacets = normalizeSubQueries(options.subQueries);
|
|
7015
|
+
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
6988
7016
|
const t0 = nowMs();
|
|
6989
7017
|
let prepMs = 0;
|
|
6990
7018
|
let factLaneMs = 0;
|
|
@@ -7005,7 +7033,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7005
7033
|
if (flags.rerank && factResults.length > 0 && hadV2Head && !didRerank) {
|
|
7006
7034
|
degraded.push("rerank-unavailable");
|
|
7007
7035
|
}
|
|
7008
|
-
if (
|
|
7036
|
+
if (usedBudget === "high" && options.decomposeOptions && !subQueries && !options.graphRefine) {
|
|
7037
|
+
degraded.push("decompose-moved");
|
|
7038
|
+
}
|
|
7009
7039
|
if (embeddingsUnavailable) degraded.push("embeddings-unavailable");
|
|
7010
7040
|
const diagnostics = {
|
|
7011
7041
|
usedBudget,
|
|
@@ -7118,10 +7148,8 @@ async function recall(query, ctx, options = {}) {
|
|
|
7118
7148
|
},
|
|
7119
7149
|
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
7120
7150
|
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
decomposeOptions: options.decomposeOptions
|
|
7124
|
-
},
|
|
7151
|
+
// 719/B4 — composite facets arrive pre-built; no LLM call here.
|
|
7152
|
+
...subQueries && { subQueries },
|
|
7125
7153
|
...options.scopes && { scopes: options.scopes },
|
|
7126
7154
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
7127
7155
|
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
@@ -7449,6 +7477,7 @@ export {
|
|
|
7449
7477
|
EMBEDDINGS_DEGRADED_EMPTY,
|
|
7450
7478
|
RerankerUnavailableError,
|
|
7451
7479
|
isRerankerAvailable,
|
|
7480
|
+
decomposeQuery,
|
|
7452
7481
|
DEFAULT_VAULT_CACHE_SIZE,
|
|
7453
7482
|
LRUCache,
|
|
7454
7483
|
createVaultEmbeddingCache,
|