@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
|
@@ -5031,6 +5031,107 @@ async function chunkAndEmbedAllMessages(ctx, options, filter) {
|
|
|
5031
5031
|
return embeddedCount;
|
|
5032
5032
|
}
|
|
5033
5033
|
|
|
5034
|
+
// src/lib/memoryVault/decomposeQuery.ts
|
|
5035
|
+
var DEFAULT_MODEL = "inclusionai/ling-2.6-flash";
|
|
5036
|
+
var MAX_SUB_QUERIES = 5;
|
|
5037
|
+
var SYSTEM_PROMPT = `You classify a memory query and, if needed, decompose it into concrete sub-queries.
|
|
5038
|
+
|
|
5039
|
+
CLASSIFICATION RULES \u2014 be strict:
|
|
5040
|
+
- "specific": asks for one fact OR a list of items in ONE category (one dimension).
|
|
5041
|
+
Examples: a name, a date, a preference, a location, an ID, a value, "what hobbies",
|
|
5042
|
+
"which conferences", "what open source projects", "what does X do for exercise".
|
|
5043
|
+
Even when the answer is a list, if all items belong to one dimension, it is specific.
|
|
5044
|
+
- "composite": asks about a person, system, or setup MULTI-DIMENSIONALLY \u2014 a summary,
|
|
5045
|
+
an overview, a profile, "tell me about X", "what is my X setup", "describe the team's
|
|
5046
|
+
X". The answer must span multiple distinct fact dimensions (e.g. for a "tech stack":
|
|
5047
|
+
language + database + framework + tools \u2014 four different dimensions).
|
|
5048
|
+
|
|
5049
|
+
When in doubt, prefer "specific". Mis-classifying a single-dimension list as composite
|
|
5050
|
+
hurts retrieval more than the reverse.
|
|
5051
|
+
|
|
5052
|
+
SUB-QUERY RULES (composite only, 3\u20135 questions):
|
|
5053
|
+
- Each sub-query targets a DIFFERENT fact dimension.
|
|
5054
|
+
- Use SHORT parenthetical examples \u2014 2\u20134 concrete options that anchor the
|
|
5055
|
+
embedding to likely memory content. Examples must be terms a user would
|
|
5056
|
+
actually have in their notes (e.g., "Postgres" not "PostgreSQL 15.2 with
|
|
5057
|
+
read replicas"). No verbose qualifiers like "and versions" or "and any
|
|
5058
|
+
relevant configuration details".
|
|
5059
|
+
- 8\u201314 words including the parenthetical. Like a human asking a follow-up.
|
|
5060
|
+
|
|
5061
|
+
Examples:
|
|
5062
|
+
"What is my dog's name?" \u2192 {"mode":"specific","subQueries":["What is my dog's name?"]}
|
|
5063
|
+
"What does the user do for exercise?" \u2192 {"mode":"specific","subQueries":["What does the user do for exercise?"]}
|
|
5064
|
+
"What conferences has the user attended?" \u2192 {"mode":"specific","subQueries":["What conferences has the user attended?"]}
|
|
5065
|
+
"What did I do last Tuesday?" \u2192 {"mode":"specific","subQueries":["What did I do last Tuesday?"]}
|
|
5066
|
+
"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)?"]}
|
|
5067
|
+
"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)?"]}
|
|
5068
|
+
"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)?"]}
|
|
5069
|
+
|
|
5070
|
+
Output strict JSON. No prose.`;
|
|
5071
|
+
async function decomposeQuery(query, options) {
|
|
5072
|
+
const fallback = { mode: "specific", subQueries: [query] };
|
|
5073
|
+
const trimmed = query.trim();
|
|
5074
|
+
if (trimmed.length === 0) return fallback;
|
|
5075
|
+
let parsed;
|
|
5076
|
+
try {
|
|
5077
|
+
parsed = await callPortalJsonCompletion({
|
|
5078
|
+
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
5079
|
+
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
5080
|
+
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
5081
|
+
model: options.model ?? DEFAULT_MODEL,
|
|
5082
|
+
systemPrompt: SYSTEM_PROMPT,
|
|
5083
|
+
// Wrap the bare query in a task framing so the model treats it as
|
|
5084
|
+
// input to classify, not as a question to answer conversationally.
|
|
5085
|
+
// Bare-query inputs caused Anthropic models to respond with prose
|
|
5086
|
+
// like "Do you mean...?" before this wrap.
|
|
5087
|
+
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.
|
|
5088
|
+
|
|
5089
|
+
Query: ${trimmed}`,
|
|
5090
|
+
// Decompose runs ahead of recall in the tool layer — tighter than the
|
|
5091
|
+
// portalLlm default (consolidate/extract can wait longer).
|
|
5092
|
+
timeoutMs: 2e4,
|
|
5093
|
+
// No internal retry: a failure degrades to the safe `{specific,[query]}`
|
|
5094
|
+
// fallback below. The agent/tool loop is the retry surface (719/B4).
|
|
5095
|
+
maxAttempts: 1,
|
|
5096
|
+
tag: "memory/decompose",
|
|
5097
|
+
...options.fetchFn && { fetchFn: options.fetchFn }
|
|
5098
|
+
});
|
|
5099
|
+
} catch (err) {
|
|
5100
|
+
getLogger().warn("memoryVault/decompose: portal call failed, falling back to specific", err);
|
|
5101
|
+
return fallback;
|
|
5102
|
+
}
|
|
5103
|
+
if (parsed === null) return fallback;
|
|
5104
|
+
return validate(parsed, trimmed) ?? fallback;
|
|
5105
|
+
}
|
|
5106
|
+
function normalizeSubQueries(raw) {
|
|
5107
|
+
if (!raw || raw.length === 0) return [];
|
|
5108
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5109
|
+
const out = [];
|
|
5110
|
+
for (const s of raw) {
|
|
5111
|
+
if (typeof s !== "string") continue;
|
|
5112
|
+
const t = s.trim();
|
|
5113
|
+
if (t.length === 0) continue;
|
|
5114
|
+
const key = t.toLowerCase();
|
|
5115
|
+
if (seen.has(key)) continue;
|
|
5116
|
+
seen.add(key);
|
|
5117
|
+
out.push(t);
|
|
5118
|
+
if (out.length >= MAX_SUB_QUERIES) break;
|
|
5119
|
+
}
|
|
5120
|
+
return out;
|
|
5121
|
+
}
|
|
5122
|
+
function validate(parsed, originalQuery) {
|
|
5123
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
5124
|
+
const obj = parsed;
|
|
5125
|
+
const mode = obj.mode === "composite" ? "composite" : "specific";
|
|
5126
|
+
if (!Array.isArray(obj.subQueries)) return null;
|
|
5127
|
+
const subQueries = normalizeSubQueries(obj.subQueries);
|
|
5128
|
+
if (subQueries.length === 0) return null;
|
|
5129
|
+
if (mode === "specific") {
|
|
5130
|
+
return { mode: "specific", subQueries: [originalQuery] };
|
|
5131
|
+
}
|
|
5132
|
+
return { mode, subQueries };
|
|
5133
|
+
}
|
|
5134
|
+
|
|
5034
5135
|
// src/lib/memory/mmr.ts
|
|
5035
5136
|
function applyMMR(candidates, k, lambda = 0.5) {
|
|
5036
5137
|
if (candidates.length === 0 || k <= 0) return [];
|
|
@@ -5408,91 +5509,6 @@ function scoreBM25(query, items) {
|
|
|
5408
5509
|
return scoreBM25Prepared(query, prepareBM25Corpus(items));
|
|
5409
5510
|
}
|
|
5410
5511
|
|
|
5411
|
-
// src/lib/memoryVault/decomposeQuery.ts
|
|
5412
|
-
var DEFAULT_MODEL = "inclusionai/ling-2.6-flash";
|
|
5413
|
-
var MAX_SUB_QUERIES = 5;
|
|
5414
|
-
var SYSTEM_PROMPT = `You classify a memory query and, if needed, decompose it into concrete sub-queries.
|
|
5415
|
-
|
|
5416
|
-
CLASSIFICATION RULES \u2014 be strict:
|
|
5417
|
-
- "specific": asks for one fact OR a list of items in ONE category (one dimension).
|
|
5418
|
-
Examples: a name, a date, a preference, a location, an ID, a value, "what hobbies",
|
|
5419
|
-
"which conferences", "what open source projects", "what does X do for exercise".
|
|
5420
|
-
Even when the answer is a list, if all items belong to one dimension, it is specific.
|
|
5421
|
-
- "composite": asks about a person, system, or setup MULTI-DIMENSIONALLY \u2014 a summary,
|
|
5422
|
-
an overview, a profile, "tell me about X", "what is my X setup", "describe the team's
|
|
5423
|
-
X". The answer must span multiple distinct fact dimensions (e.g. for a "tech stack":
|
|
5424
|
-
language + database + framework + tools \u2014 four different dimensions).
|
|
5425
|
-
|
|
5426
|
-
When in doubt, prefer "specific". Mis-classifying a single-dimension list as composite
|
|
5427
|
-
hurts retrieval more than the reverse.
|
|
5428
|
-
|
|
5429
|
-
SUB-QUERY RULES (composite only, 3\u20135 questions):
|
|
5430
|
-
- Each sub-query targets a DIFFERENT fact dimension.
|
|
5431
|
-
- Use SHORT parenthetical examples \u2014 2\u20134 concrete options that anchor the
|
|
5432
|
-
embedding to likely memory content. Examples must be terms a user would
|
|
5433
|
-
actually have in their notes (e.g., "Postgres" not "PostgreSQL 15.2 with
|
|
5434
|
-
read replicas"). No verbose qualifiers like "and versions" or "and any
|
|
5435
|
-
relevant configuration details".
|
|
5436
|
-
- 8\u201314 words including the parenthetical. Like a human asking a follow-up.
|
|
5437
|
-
|
|
5438
|
-
Examples:
|
|
5439
|
-
"What is my dog's name?" \u2192 {"mode":"specific","subQueries":["What is my dog's name?"]}
|
|
5440
|
-
"What does the user do for exercise?" \u2192 {"mode":"specific","subQueries":["What does the user do for exercise?"]}
|
|
5441
|
-
"What conferences has the user attended?" \u2192 {"mode":"specific","subQueries":["What conferences has the user attended?"]}
|
|
5442
|
-
"What did I do last Tuesday?" \u2192 {"mode":"specific","subQueries":["What did I do last Tuesday?"]}
|
|
5443
|
-
"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)?"]}
|
|
5444
|
-
"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)?"]}
|
|
5445
|
-
"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)?"]}
|
|
5446
|
-
|
|
5447
|
-
Output strict JSON. No prose.`;
|
|
5448
|
-
async function decomposeQuery(query, options) {
|
|
5449
|
-
const fallback = { mode: "specific", subQueries: [query] };
|
|
5450
|
-
const trimmed = query.trim();
|
|
5451
|
-
if (trimmed.length === 0) return fallback;
|
|
5452
|
-
let parsed;
|
|
5453
|
-
try {
|
|
5454
|
-
parsed = await callPortalJsonCompletion({
|
|
5455
|
-
...options.apiKey !== void 0 && { apiKey: options.apiKey },
|
|
5456
|
-
...options.getToken !== void 0 && { getToken: options.getToken },
|
|
5457
|
-
...options.baseUrl !== void 0 && { baseUrl: options.baseUrl },
|
|
5458
|
-
model: options.model ?? DEFAULT_MODEL,
|
|
5459
|
-
systemPrompt: SYSTEM_PROMPT,
|
|
5460
|
-
// Wrap the bare query in a task framing so the model treats it as
|
|
5461
|
-
// input to classify, not as a question to answer conversationally.
|
|
5462
|
-
// Bare-query inputs caused Anthropic models to respond with prose
|
|
5463
|
-
// like "Do you mean...?" before this wrap.
|
|
5464
|
-
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.
|
|
5465
|
-
|
|
5466
|
-
Query: ${trimmed}`,
|
|
5467
|
-
// Decompose runs on the recall hot path — tighter than the
|
|
5468
|
-
// portalLlm default (consolidate/extract can wait longer).
|
|
5469
|
-
timeoutMs: 2e4,
|
|
5470
|
-
// No internal retry: a failure degrades to the safe `{specific,[query]}`
|
|
5471
|
-
// fallback below, so retrying would only add latency on the hot path.
|
|
5472
|
-
maxAttempts: 1,
|
|
5473
|
-
tag: "memory/decompose",
|
|
5474
|
-
...options.fetchFn && { fetchFn: options.fetchFn }
|
|
5475
|
-
});
|
|
5476
|
-
} catch (err) {
|
|
5477
|
-
getLogger().warn("memoryVault/decompose: portal call failed, falling back to specific", err);
|
|
5478
|
-
return fallback;
|
|
5479
|
-
}
|
|
5480
|
-
if (parsed === null) return fallback;
|
|
5481
|
-
return validate(parsed, trimmed) ?? fallback;
|
|
5482
|
-
}
|
|
5483
|
-
function validate(parsed, originalQuery) {
|
|
5484
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
5485
|
-
const obj = parsed;
|
|
5486
|
-
const mode = obj.mode === "composite" ? "composite" : "specific";
|
|
5487
|
-
if (!Array.isArray(obj.subQueries)) return null;
|
|
5488
|
-
const subQueries = obj.subQueries.filter((s) => typeof s === "string").map((s) => s.trim()).filter((s) => s.length > 0).slice(0, MAX_SUB_QUERIES);
|
|
5489
|
-
if (subQueries.length === 0) return null;
|
|
5490
|
-
if (mode === "specific") {
|
|
5491
|
-
return { mode: "specific", subQueries: [originalQuery] };
|
|
5492
|
-
}
|
|
5493
|
-
return { mode, subQueries };
|
|
5494
|
-
}
|
|
5495
|
-
|
|
5496
5512
|
// src/lib/memoryVault/lruCache.ts
|
|
5497
5513
|
var DEFAULT_VAULT_CACHE_SIZE = 5e3;
|
|
5498
5514
|
var LRUCache = class extends Map {
|
|
@@ -5526,6 +5542,7 @@ function createVaultEmbeddingCache(maxSize = DEFAULT_VAULT_CACHE_SIZE) {
|
|
|
5526
5542
|
}
|
|
5527
5543
|
|
|
5528
5544
|
// src/lib/memoryVault/searchTool.ts
|
|
5545
|
+
var warnedProgrammaticDecomposeIgnored = false;
|
|
5529
5546
|
function normalizeEventTimeKind(kind) {
|
|
5530
5547
|
return kind === "point" || kind === "range" || kind === "ongoing" ? kind : null;
|
|
5531
5548
|
}
|
|
@@ -6460,52 +6477,51 @@ async function rankPreparedVaultCandidates(query, prepared, embeddingOptions, se
|
|
|
6460
6477
|
...searchOptions?.rrfK !== void 0 && { rrfK: searchOptions.rrfK },
|
|
6461
6478
|
...searchOptions?.factTypeWeights && { factTypeWeights: searchOptions.factTypeWeights }
|
|
6462
6479
|
};
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
}
|
|
6480
|
+
const normalizedFacets = normalizeSubQueries(searchOptions?.subQueries);
|
|
6481
|
+
const facetQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
6482
|
+
if (useFusion && !embeddingsUnavailable && facetQueries) {
|
|
6483
|
+
let subEmbeddings;
|
|
6484
|
+
try {
|
|
6485
|
+
subEmbeddings = await generateEmbeddings(facetQueries, embeddingOptions);
|
|
6486
|
+
} catch (err) {
|
|
6487
|
+
getLogger().warn(
|
|
6488
|
+
"memoryVault: sub-query embedding failed \u2014 falling back to single-query ranking: " + (err instanceof Error ? err.message : String(err))
|
|
6489
|
+
);
|
|
6490
|
+
subEmbeddings = [];
|
|
6491
|
+
}
|
|
6492
|
+
const subEmbeddingsUsable = facetQueries.length > 0 && subEmbeddings.length === facetQueries.length && subEmbeddings.every((v) => v.length > 0 && v.length === queryEmbedding.length);
|
|
6493
|
+
if (subEmbeddings.length > 0 && !subEmbeddingsUsable) {
|
|
6494
|
+
getLogger().warn(
|
|
6495
|
+
`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`
|
|
6496
|
+
);
|
|
6497
|
+
}
|
|
6498
|
+
if (subEmbeddingsUsable) {
|
|
6499
|
+
const subQueries = facetQueries.map((sq, i) => ({
|
|
6500
|
+
query: sq,
|
|
6501
|
+
embedding: subEmbeddings[i]
|
|
6502
|
+
}));
|
|
6503
|
+
const v2HeadStats = { hadResults: false };
|
|
6504
|
+
const composite = await rankComposite(query, queryEmbedding, subQueries, embeddedItems, {
|
|
6505
|
+
limit,
|
|
6506
|
+
minSimilarity,
|
|
6507
|
+
rerank: !!searchOptions?.rerank,
|
|
6508
|
+
...searchOptions?.rerankTopN !== void 0 && {
|
|
6509
|
+
rerankTopN: searchOptions.rerankTopN
|
|
6510
|
+
},
|
|
6511
|
+
...searchOptions?.ceWeight !== void 0 && { ceWeight: searchOptions.ceWeight },
|
|
6512
|
+
...searchOptions?.mmr !== void 0 && { mmr: searchOptions.mmr },
|
|
6513
|
+
...tuning,
|
|
6514
|
+
...searchOptions?.entityRanking && { entityRanking: searchOptions.entityRanking },
|
|
6515
|
+
...searchOptions?.temporalRanking && { temporalRanking: searchOptions.temporalRanking },
|
|
6516
|
+
rerankStats,
|
|
6517
|
+
v2HeadStats
|
|
6518
|
+
});
|
|
6519
|
+
return stampTimestamps({
|
|
6520
|
+
results: composite,
|
|
6521
|
+
vaultSize,
|
|
6522
|
+
reranked: rerankStats.applied,
|
|
6523
|
+
hadV2Head: v2HeadStats.hadResults
|
|
6524
|
+
});
|
|
6509
6525
|
}
|
|
6510
6526
|
}
|
|
6511
6527
|
if (useFusion && searchOptions?.rerank) {
|
|
@@ -6565,6 +6581,12 @@ async function searchVaultMemoriesWithSize(query, vaultCtx, embeddingOptions, ca
|
|
|
6565
6581
|
rankedOnCosine: false
|
|
6566
6582
|
};
|
|
6567
6583
|
}
|
|
6584
|
+
if (searchOptions?.decompose === "llm" && normalizeSubQueries(searchOptions.subQueries).length < 2 && !warnedProgrammaticDecomposeIgnored) {
|
|
6585
|
+
warnedProgrammaticDecomposeIgnored = true;
|
|
6586
|
+
getLogger().warn(
|
|
6587
|
+
'memoryVault: decompose:"llm" is ignored by searchVaultMemories \u2014 pass subQueries or use createMemoryVaultSearchTool / createRecallTool (719/B4)'
|
|
6588
|
+
);
|
|
6589
|
+
}
|
|
6568
6590
|
const prepared = await prepareVaultCandidates(
|
|
6569
6591
|
query,
|
|
6570
6592
|
vaultCtx,
|
|
@@ -6670,7 +6692,8 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6670
6692
|
return "Error: A search query is required.";
|
|
6671
6693
|
}
|
|
6672
6694
|
try {
|
|
6673
|
-
const
|
|
6695
|
+
const wantsDecompose = searchOptions?.decompose === "llm" && !!searchOptions.decomposeOptions;
|
|
6696
|
+
const budget = wantsDecompose ? "high" : searchOptions?.rerank ? "mid" : "low";
|
|
6674
6697
|
const folderId = searchOptions?.folderId ?? argFolderId;
|
|
6675
6698
|
if (searchOptions?.useFusion === false) {
|
|
6676
6699
|
const { results: legacy, embeddingsUnavailable } = await searchVaultMemoriesWithSize(
|
|
@@ -6694,7 +6717,14 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6694
6717
|
legacy.map((r) => ({ id: r.uniqueId, content: r.content, score: r.similarity }))
|
|
6695
6718
|
);
|
|
6696
6719
|
}
|
|
6697
|
-
|
|
6720
|
+
let subQueries;
|
|
6721
|
+
if (wantsDecompose && searchOptions?.decomposeOptions) {
|
|
6722
|
+
const decomp = await decomposeQuery(query, searchOptions.decomposeOptions);
|
|
6723
|
+
if (decomp.mode === "composite" && decomp.subQueries.length >= 2) {
|
|
6724
|
+
subQueries = decomp.subQueries;
|
|
6725
|
+
}
|
|
6726
|
+
}
|
|
6727
|
+
const { recall: recall2 } = await import("./recall-DVX4W2UD.mjs");
|
|
6698
6728
|
let recallDegraded = [];
|
|
6699
6729
|
const result = await recall2(
|
|
6700
6730
|
query,
|
|
@@ -6710,9 +6740,7 @@ function createMemoryVaultSearchTool(vaultCtx, embeddingOptions, cache, searchOp
|
|
|
6710
6740
|
...tuningForward,
|
|
6711
6741
|
...folderId !== void 0 && { folderId },
|
|
6712
6742
|
...searchOptions?.scopes && { scopes: searchOptions.scopes },
|
|
6713
|
-
...
|
|
6714
|
-
decomposeOptions: searchOptions.decomposeOptions
|
|
6715
|
-
}
|
|
6743
|
+
...subQueries && { subQueries }
|
|
6716
6744
|
}
|
|
6717
6745
|
);
|
|
6718
6746
|
if (result.vaultSize === 0) {
|
|
@@ -7240,12 +7268,12 @@ var DEFAULT_CHUNK_MIN_SCORE = 0.5;
|
|
|
7240
7268
|
function flagsForBudget(budget) {
|
|
7241
7269
|
switch (budget) {
|
|
7242
7270
|
case "high":
|
|
7243
|
-
return { rerank: true,
|
|
7271
|
+
return { rerank: true, traverse: true };
|
|
7244
7272
|
case "mid":
|
|
7245
|
-
return { rerank: true,
|
|
7273
|
+
return { rerank: true, traverse: false };
|
|
7246
7274
|
case "low":
|
|
7247
7275
|
default:
|
|
7248
|
-
return { rerank: false,
|
|
7276
|
+
return { rerank: false, traverse: false };
|
|
7249
7277
|
}
|
|
7250
7278
|
}
|
|
7251
7279
|
function dedupeBy(items, ...keys) {
|
|
@@ -7264,10 +7292,10 @@ function dedupeBy(items, ...keys) {
|
|
|
7264
7292
|
async function recall(query, ctx, options = {}) {
|
|
7265
7293
|
const types = options.types ?? ["fact"];
|
|
7266
7294
|
const limit = options.limit ?? DEFAULT_LIMIT;
|
|
7267
|
-
const
|
|
7268
|
-
const flags = flagsForBudget(
|
|
7269
|
-
const
|
|
7270
|
-
const
|
|
7295
|
+
const usedBudget = options.budget ?? DEFAULT_BUDGET;
|
|
7296
|
+
const flags = flagsForBudget(usedBudget);
|
|
7297
|
+
const normalizedFacets = normalizeSubQueries(options.subQueries);
|
|
7298
|
+
const subQueries = normalizedFacets.length >= 2 ? normalizedFacets : void 0;
|
|
7271
7299
|
const t0 = nowMs();
|
|
7272
7300
|
let prepMs = 0;
|
|
7273
7301
|
let factLaneMs = 0;
|
|
@@ -7288,7 +7316,9 @@ async function recall(query, ctx, options = {}) {
|
|
|
7288
7316
|
if (flags.rerank && factResults.length > 0 && hadV2Head && !didRerank) {
|
|
7289
7317
|
degraded.push("rerank-unavailable");
|
|
7290
7318
|
}
|
|
7291
|
-
if (
|
|
7319
|
+
if (usedBudget === "high" && options.decomposeOptions && !subQueries && !options.graphRefine) {
|
|
7320
|
+
degraded.push("decompose-moved");
|
|
7321
|
+
}
|
|
7292
7322
|
if (embeddingsUnavailable) degraded.push("embeddings-unavailable");
|
|
7293
7323
|
const diagnostics = {
|
|
7294
7324
|
usedBudget,
|
|
@@ -7401,10 +7431,8 @@ async function recall(query, ctx, options = {}) {
|
|
|
7401
7431
|
},
|
|
7402
7432
|
...options.rrfK !== void 0 && { rrfK: options.rrfK },
|
|
7403
7433
|
...options.decryptLast !== void 0 && { decryptLast: options.decryptLast },
|
|
7404
|
-
|
|
7405
|
-
|
|
7406
|
-
decomposeOptions: options.decomposeOptions
|
|
7407
|
-
},
|
|
7434
|
+
// 719/B4 — composite facets arrive pre-built; no LLM call here.
|
|
7435
|
+
...subQueries && { subQueries },
|
|
7408
7436
|
...options.scopes && { scopes: options.scopes },
|
|
7409
7437
|
...options.folderId !== void 0 && { folderId: options.folderId },
|
|
7410
7438
|
...options.factTypes?.length && { factTypes: options.factTypes },
|
|
@@ -7777,6 +7805,7 @@ export {
|
|
|
7777
7805
|
EMBEDDINGS_DEGRADED_EMPTY,
|
|
7778
7806
|
RerankerUnavailableError,
|
|
7779
7807
|
isRerankerAvailable,
|
|
7808
|
+
decomposeQuery,
|
|
7780
7809
|
DEFAULT_VAULT_CACHE_SIZE,
|
|
7781
7810
|
LRUCache,
|
|
7782
7811
|
createVaultEmbeddingCache,
|