neuro-vault-mcp 8.2.0 → 9.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/cli.d.ts +0 -1
- package/dist/cli.js +153 -157
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -15896,28 +15896,26 @@ var MODE_DEFAULTS = {
|
|
|
15896
15896
|
quick: { limit: 3, threshold: 0.5, expansion: false, expansionLimit: 0 },
|
|
15897
15897
|
deep: { limit: 8, threshold: 0.35, expansion: true, expansionLimit: 3 }
|
|
15898
15898
|
};
|
|
15899
|
-
function
|
|
15900
|
-
const {
|
|
15901
|
-
const
|
|
15902
|
-
const
|
|
15903
|
-
for (const
|
|
15904
|
-
const source = sources.get(
|
|
15905
|
-
if (!source || source.embedding.length === 0)
|
|
15906
|
-
|
|
15899
|
+
function computeRelatedPerSeed(args) {
|
|
15900
|
+
const { seedPaths, sources, searchEngine, threshold, perSeedLimit } = args;
|
|
15901
|
+
const seedSet = new Set(seedPaths);
|
|
15902
|
+
const out = /* @__PURE__ */ new Map();
|
|
15903
|
+
for (const seedPath of seedPaths) {
|
|
15904
|
+
const source = sources.get(seedPath);
|
|
15905
|
+
if (!source || source.embedding.length === 0) {
|
|
15906
|
+
out.set(seedPath, []);
|
|
15907
|
+
continue;
|
|
15908
|
+
}
|
|
15909
|
+
const neighbours = searchEngine.findNeighbors({
|
|
15907
15910
|
queryVector: source.embedding,
|
|
15908
15911
|
sources: sources.values(),
|
|
15909
15912
|
threshold,
|
|
15910
|
-
limit: perSeedLimit
|
|
15913
|
+
limit: perSeedLimit + seedSet.size
|
|
15911
15914
|
});
|
|
15912
|
-
|
|
15913
|
-
|
|
15914
|
-
const cur = bestByPath.get(n.path);
|
|
15915
|
-
if (cur === void 0 || n.similarity > cur) {
|
|
15916
|
-
bestByPath.set(n.path, n.similarity);
|
|
15917
|
-
}
|
|
15918
|
-
}
|
|
15915
|
+
const related = neighbours.filter((n) => !seedSet.has(n.path)).sort((a, b) => b.similarity - a.similarity || a.path.localeCompare(b.path)).slice(0, perSeedLimit).map((n) => ({ path: n.path, expansion_similarity: n.similarity }));
|
|
15916
|
+
out.set(seedPath, related);
|
|
15919
15917
|
}
|
|
15920
|
-
return
|
|
15918
|
+
return out;
|
|
15921
15919
|
}
|
|
15922
15920
|
async function executeRetrieval(input) {
|
|
15923
15921
|
const { query, mode, sources, embeddingProvider, searchEngine } = input;
|
|
@@ -15941,40 +15939,50 @@ async function executeRetrieval(input) {
|
|
|
15941
15939
|
limit
|
|
15942
15940
|
});
|
|
15943
15941
|
}
|
|
15944
|
-
|
|
15945
|
-
|
|
15946
|
-
|
|
15942
|
+
const seeds = vectorResults.slice(0, limit);
|
|
15943
|
+
const seedPaths = seeds.map((s) => s.path);
|
|
15944
|
+
const seedPathSet = new Set(seedPaths);
|
|
15945
|
+
const blocksByPath = /* @__PURE__ */ new Map();
|
|
15946
|
+
if (seeds.length > 0) {
|
|
15947
|
+
const seedSources = [...sources.values()].filter((s) => seedPathSet.has(s.path));
|
|
15948
|
+
const rawBlocks = mode === "deep" ? searchEngine.findBlockNeighbors({
|
|
15947
15949
|
queryVector,
|
|
15948
|
-
sources:
|
|
15950
|
+
sources: seedSources,
|
|
15949
15951
|
threshold,
|
|
15950
15952
|
limit
|
|
15951
|
-
})
|
|
15952
|
-
} else if (vectorResults.length > 0) {
|
|
15953
|
-
const matchedPaths = new Set(vectorResults.map((r) => r.path));
|
|
15954
|
-
const matchedSources = [...sources.values()].filter((s) => matchedPaths.has(s.path));
|
|
15955
|
-
blockResults = searchEngine.findBlockNeighbors({
|
|
15953
|
+
}) : searchEngine.findBlockNeighbors({
|
|
15956
15954
|
queryVector,
|
|
15957
|
-
sources:
|
|
15955
|
+
sources: seedSources,
|
|
15958
15956
|
threshold: 0,
|
|
15959
15957
|
limit: QUICK_BLOCK_LIMIT
|
|
15960
15958
|
});
|
|
15959
|
+
for (const block of rawBlocks) {
|
|
15960
|
+
if (!seedPathSet.has(block.path)) continue;
|
|
15961
|
+
const bucket = blocksByPath.get(block.path) ?? [];
|
|
15962
|
+
bucket.push({ heading: block.heading, lines: block.lines, similarity: block.similarity });
|
|
15963
|
+
blocksByPath.set(block.path, bucket);
|
|
15964
|
+
}
|
|
15965
|
+
for (const bucket of blocksByPath.values()) {
|
|
15966
|
+
bucket.sort((a, b) => b.similarity - a.similarity || a.lines[0] - b.lines[0]);
|
|
15967
|
+
}
|
|
15961
15968
|
}
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
seeds: cappedSeeds,
|
|
15969
|
+
let relatedByPath = /* @__PURE__ */ new Map();
|
|
15970
|
+
if (expansion && expansionLimit > 0 && seeds.length > 0) {
|
|
15971
|
+
relatedByPath = computeRelatedPerSeed({
|
|
15972
|
+
seedPaths,
|
|
15967
15973
|
sources,
|
|
15968
15974
|
searchEngine,
|
|
15969
15975
|
threshold,
|
|
15970
|
-
perSeedLimit:
|
|
15971
|
-
totalLimit: expansionLimit
|
|
15976
|
+
perSeedLimit: expansionLimit
|
|
15972
15977
|
});
|
|
15973
15978
|
}
|
|
15974
|
-
|
|
15975
|
-
|
|
15976
|
-
|
|
15977
|
-
|
|
15979
|
+
const results = seeds.map((seed) => ({
|
|
15980
|
+
path: seed.path,
|
|
15981
|
+
similarity: seed.similarity,
|
|
15982
|
+
blocks: blocksByPath.get(seed.path) ?? [],
|
|
15983
|
+
related: relatedByPath.get(seed.path) ?? []
|
|
15984
|
+
}));
|
|
15985
|
+
return { results };
|
|
15978
15986
|
}
|
|
15979
15987
|
function mergeNoteResults(perQuery) {
|
|
15980
15988
|
const byPath = /* @__PURE__ */ new Map();
|
|
@@ -15992,7 +16000,6 @@ function mergeNoteResults(perQuery) {
|
|
|
15992
16000
|
if (result.similarity > existing.similarity) {
|
|
15993
16001
|
existing.similarity = result.similarity;
|
|
15994
16002
|
}
|
|
15995
|
-
existing.matched_queries ??= [];
|
|
15996
16003
|
if (!existing.matched_queries.includes(query)) {
|
|
15997
16004
|
existing.matched_queries.push(query);
|
|
15998
16005
|
}
|
|
@@ -16002,34 +16009,6 @@ function mergeNoteResults(perQuery) {
|
|
|
16002
16009
|
(a, b) => b.similarity - a.similarity || a.path.localeCompare(b.path)
|
|
16003
16010
|
);
|
|
16004
16011
|
}
|
|
16005
|
-
function mergeBlockResults(perQuery) {
|
|
16006
|
-
const byKey = /* @__PURE__ */ new Map();
|
|
16007
|
-
for (const { query, blocks } of perQuery) {
|
|
16008
|
-
for (const block of blocks) {
|
|
16009
|
-
const key = `${block.path}\0${block.heading}\0${block.lines[0]}-${block.lines[1]}`;
|
|
16010
|
-
const existing = byKey.get(key);
|
|
16011
|
-
if (!existing) {
|
|
16012
|
-
byKey.set(key, {
|
|
16013
|
-
path: block.path,
|
|
16014
|
-
heading: block.heading,
|
|
16015
|
-
lines: block.lines,
|
|
16016
|
-
similarity: block.similarity,
|
|
16017
|
-
matched_queries: [query]
|
|
16018
|
-
});
|
|
16019
|
-
continue;
|
|
16020
|
-
}
|
|
16021
|
-
if (block.similarity > existing.similarity) {
|
|
16022
|
-
existing.similarity = block.similarity;
|
|
16023
|
-
}
|
|
16024
|
-
if (!existing.matched_queries.includes(query)) {
|
|
16025
|
-
existing.matched_queries.push(query);
|
|
16026
|
-
}
|
|
16027
|
-
}
|
|
16028
|
-
}
|
|
16029
|
-
return [...byKey.values()].sort(
|
|
16030
|
-
(a, b) => b.similarity - a.similarity || a.path.localeCompare(b.path)
|
|
16031
|
-
);
|
|
16032
|
-
}
|
|
16033
16012
|
async function executeMultiRetrieval(input) {
|
|
16034
16013
|
const { queries, mode, sources, embeddingProvider, searchEngine } = input;
|
|
16035
16014
|
const modeConfig = MODE_DEFAULTS[mode];
|
|
@@ -16054,57 +16033,77 @@ async function executeMultiRetrieval(input) {
|
|
|
16054
16033
|
limit
|
|
16055
16034
|
});
|
|
16056
16035
|
}
|
|
16057
|
-
|
|
16058
|
-
if (mode === "deep") {
|
|
16059
|
-
blocks = searchEngine.findBlockNeighbors({
|
|
16060
|
-
queryVector,
|
|
16061
|
-
sources: sources.values(),
|
|
16062
|
-
threshold,
|
|
16063
|
-
limit
|
|
16064
|
-
});
|
|
16065
|
-
} else if (neighbors.length > 0) {
|
|
16066
|
-
const matched = new Set(neighbors.map((r) => r.path));
|
|
16067
|
-
const matchedSources = [...sources.values()].filter((s) => matched.has(s.path));
|
|
16068
|
-
blocks = searchEngine.findBlockNeighbors({
|
|
16069
|
-
queryVector,
|
|
16070
|
-
sources: matchedSources,
|
|
16071
|
-
threshold: 0,
|
|
16072
|
-
limit: QUICK_BLOCK_LIMIT
|
|
16073
|
-
});
|
|
16074
|
-
}
|
|
16075
|
-
return { query, neighbors, blocks };
|
|
16036
|
+
return { query, queryVector, neighbors };
|
|
16076
16037
|
})
|
|
16077
16038
|
);
|
|
16078
|
-
const
|
|
16039
|
+
const merged = mergeNoteResults(
|
|
16079
16040
|
perQueryOutputs.map(({ query, neighbors }) => ({ query, results: neighbors }))
|
|
16080
16041
|
);
|
|
16081
|
-
const
|
|
16082
|
-
const
|
|
16083
|
-
const
|
|
16084
|
-
const
|
|
16085
|
-
const
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
const
|
|
16089
|
-
const
|
|
16090
|
-
|
|
16042
|
+
const truncated = merged.length > limit;
|
|
16043
|
+
const seeds = merged.slice(0, limit);
|
|
16044
|
+
const seedPaths = seeds.map((s) => s.path);
|
|
16045
|
+
const seedPathSet = new Set(seedPaths);
|
|
16046
|
+
const blocksByPath = /* @__PURE__ */ new Map();
|
|
16047
|
+
if (seeds.length > 0) {
|
|
16048
|
+
const seedSources = [...sources.values()].filter((s) => seedPathSet.has(s.path));
|
|
16049
|
+
const rawByKey = /* @__PURE__ */ new Map();
|
|
16050
|
+
for (const { queryVector } of perQueryOutputs) {
|
|
16051
|
+
const raw = mode === "deep" ? searchEngine.findBlockNeighbors({
|
|
16052
|
+
queryVector,
|
|
16053
|
+
sources: seedSources,
|
|
16054
|
+
threshold,
|
|
16055
|
+
limit
|
|
16056
|
+
}) : searchEngine.findBlockNeighbors({
|
|
16057
|
+
queryVector,
|
|
16058
|
+
sources: seedSources,
|
|
16059
|
+
threshold: 0,
|
|
16060
|
+
limit: QUICK_BLOCK_LIMIT
|
|
16061
|
+
});
|
|
16062
|
+
for (const block of raw) {
|
|
16063
|
+
if (!seedPathSet.has(block.path)) continue;
|
|
16064
|
+
const key = `${block.path}\0${block.heading}\0${block.lines[0]}-${block.lines[1]}`;
|
|
16065
|
+
const existing = rawByKey.get(key);
|
|
16066
|
+
if (!existing || block.similarity > existing.similarity) {
|
|
16067
|
+
rawByKey.set(key, {
|
|
16068
|
+
path: block.path,
|
|
16069
|
+
heading: block.heading,
|
|
16070
|
+
lines: block.lines,
|
|
16071
|
+
similarity: block.similarity
|
|
16072
|
+
});
|
|
16073
|
+
}
|
|
16074
|
+
}
|
|
16075
|
+
}
|
|
16076
|
+
for (const block of rawByKey.values()) {
|
|
16077
|
+
const bucket = blocksByPath.get(block.path) ?? [];
|
|
16078
|
+
bucket.push({
|
|
16079
|
+
heading: block.heading,
|
|
16080
|
+
lines: block.lines,
|
|
16081
|
+
similarity: block.similarity
|
|
16082
|
+
});
|
|
16083
|
+
blocksByPath.set(block.path, bucket);
|
|
16084
|
+
}
|
|
16085
|
+
for (const bucket of blocksByPath.values()) {
|
|
16086
|
+
bucket.sort((a, b) => b.similarity - a.similarity || a.lines[0] - b.lines[0]);
|
|
16087
|
+
}
|
|
16088
|
+
}
|
|
16089
|
+
let relatedByPath = /* @__PURE__ */ new Map();
|
|
16090
|
+
if (expansion && expansionLimit > 0 && seeds.length > 0) {
|
|
16091
|
+
relatedByPath = computeRelatedPerSeed({
|
|
16092
|
+
seedPaths,
|
|
16091
16093
|
sources,
|
|
16092
16094
|
searchEngine,
|
|
16093
16095
|
threshold,
|
|
16094
|
-
perSeedLimit:
|
|
16095
|
-
totalLimit: expansionLimit
|
|
16096
|
+
perSeedLimit: expansionLimit
|
|
16096
16097
|
});
|
|
16097
|
-
expansionResults = raw.map((r) => ({
|
|
16098
|
-
path: r.path,
|
|
16099
|
-
similarity: r.similarity,
|
|
16100
|
-
via_expansion: true
|
|
16101
|
-
}));
|
|
16102
16098
|
}
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16099
|
+
const results = seeds.map((seed) => ({
|
|
16100
|
+
path: seed.path,
|
|
16101
|
+
similarity: seed.similarity,
|
|
16102
|
+
matched_queries: seed.matched_queries,
|
|
16103
|
+
blocks: blocksByPath.get(seed.path) ?? [],
|
|
16104
|
+
related: relatedByPath.get(seed.path) ?? []
|
|
16105
|
+
}));
|
|
16106
|
+
return { results, truncated };
|
|
16108
16107
|
}
|
|
16109
16108
|
|
|
16110
16109
|
// src/modules/semantic/tools/search-notes.ts
|
|
@@ -16185,12 +16184,7 @@ async function runSearchForEntry(entry, input, deps) {
|
|
|
16185
16184
|
}
|
|
16186
16185
|
if (allowed.size === 0) {
|
|
16187
16186
|
const isMulti = Array.isArray(input.query);
|
|
16188
|
-
|
|
16189
|
-
return {
|
|
16190
|
-
results: [],
|
|
16191
|
-
...isDeep ? { blockResults: [] } : {},
|
|
16192
|
-
...isMulti ? { truncated: false } : {}
|
|
16193
|
-
};
|
|
16187
|
+
return isMulti ? { results: [], truncated: false } : { results: [] };
|
|
16194
16188
|
}
|
|
16195
16189
|
effectiveSources = narrowSources(sources, allowed);
|
|
16196
16190
|
}
|
|
@@ -16208,23 +16202,19 @@ async function runSearchForEntry(entry, input, deps) {
|
|
|
16208
16202
|
});
|
|
16209
16203
|
const candidatePaths = [
|
|
16210
16204
|
...output.results.map((r) => r.path),
|
|
16211
|
-
...output.
|
|
16205
|
+
...output.results.flatMap((r) => r.related.map((rel) => rel.path))
|
|
16212
16206
|
];
|
|
16213
16207
|
const [existing] = await Promise.all([
|
|
16214
16208
|
buildExistingPathSet2(entry, candidatePaths),
|
|
16215
16209
|
graph.ensureFresh()
|
|
16216
16210
|
]);
|
|
16217
|
-
|
|
16218
|
-
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
blockResults: output.blockResults.filter((b) => existing.has(b.path)).map((b) => ({ ...b, vault: entry.name }))
|
|
16225
|
-
} : {},
|
|
16226
|
-
truncated: output.truncated
|
|
16227
|
-
};
|
|
16211
|
+
const enriched = output.results.filter((r) => existing.has(r.path)).map((r) => ({
|
|
16212
|
+
...r,
|
|
16213
|
+
related: r.related.filter((rel) => existing.has(rel.path)),
|
|
16214
|
+
backlink_count: graph.getBacklinkCount(r.path),
|
|
16215
|
+
vault: entry.name
|
|
16216
|
+
}));
|
|
16217
|
+
return { results: enriched, truncated: output.truncated };
|
|
16228
16218
|
} catch (error48) {
|
|
16229
16219
|
throw wrapDependencyError2(error48, "Failed to search notes", {
|
|
16230
16220
|
modelKey,
|
|
@@ -16245,22 +16235,19 @@ async function runSearchForEntry(entry, input, deps) {
|
|
|
16245
16235
|
});
|
|
16246
16236
|
const candidatePaths = [
|
|
16247
16237
|
...output.results.map((r) => r.path),
|
|
16248
|
-
...output.
|
|
16238
|
+
...output.results.flatMap((r) => r.related.map((rel) => rel.path))
|
|
16249
16239
|
];
|
|
16250
16240
|
const [existing] = await Promise.all([
|
|
16251
16241
|
buildExistingPathSet2(entry, candidatePaths),
|
|
16252
16242
|
graph.ensureFresh()
|
|
16253
16243
|
]);
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
blockResults: output.blockResults.filter((b) => existing.has(b.path)).map((b) => ({ ...b, vault: entry.name }))
|
|
16262
|
-
} : {}
|
|
16263
|
-
};
|
|
16244
|
+
const enriched = output.results.filter((r) => existing.has(r.path)).map((r) => ({
|
|
16245
|
+
...r,
|
|
16246
|
+
related: r.related.filter((rel) => existing.has(rel.path)),
|
|
16247
|
+
backlink_count: graph.getBacklinkCount(r.path),
|
|
16248
|
+
vault: entry.name
|
|
16249
|
+
}));
|
|
16250
|
+
return { results: enriched };
|
|
16264
16251
|
} catch (error48) {
|
|
16265
16252
|
throw wrapDependencyError2(error48, "Failed to search notes", {
|
|
16266
16253
|
modelKey,
|
|
@@ -16283,36 +16270,45 @@ function buildSearchNotesTool(deps) {
|
|
|
16283
16270
|
"Search notes by semantic similarity. Best for fuzzy recall, topic exploration, or cross-language matches. Pass short keyword queries (1-4 words), not sentences.",
|
|
16284
16271
|
"",
|
|
16285
16272
|
"MODES (pick based on intent):",
|
|
16286
|
-
'- "quick" (default) \u2014 specific lookup. Returns up to 3
|
|
16287
|
-
'- "deep" \u2014 topic exploration. Returns up to 8 notes
|
|
16273
|
+
'- "quick" (default) \u2014 specific lookup. Returns up to 3 notes; each note carries `blocks[]` scoped to itself and `related: []`. Use when you want one or two specific notes.',
|
|
16274
|
+
'- "deep" \u2014 topic exploration. Returns up to 8 notes; each note carries `blocks[]` (scoped to itself) and `related[]` (semantically neighbouring notes). Use for "tell me about X" or building an overview.',
|
|
16288
16275
|
"",
|
|
16289
16276
|
"PARAMETERS:",
|
|
16290
|
-
"- query (required): string, or array of 1-8 strings. Pass an array for synonyms / reformulations / translations \u2014 embedded in batch, merged into one ranked list. Each result carries `matched_queries` (which of your queries hit it). `limit` is the FINAL result count regardless of how many queries are passed
|
|
16277
|
+
"- query (required): string, or array of 1-8 strings. Pass an array for synonyms / reformulations / translations \u2014 embedded in batch, merged into one ranked list. Each result carries `matched_queries` (which of your queries hit it). `limit` is the FINAL result count regardless of how many queries are passed.",
|
|
16291
16278
|
'- mode: "quick" | "deep" (default "quick").',
|
|
16292
|
-
"- limit: max notes in `results`. Default 3 (quick) / 8 (deep).
|
|
16279
|
+
"- limit: max notes in `results`. Default 3 (quick) / 8 (deep). Does not affect leaves (`blocks` / `related`).",
|
|
16293
16280
|
"- threshold: min similarity, 0-1. Default 0.5 (quick) / 0.35 (deep). Raise to 0.6+ to cut weak matches; lower (e.g. 0.3) when nothing comes back.",
|
|
16294
16281
|
...registry2.isMulti() ? ["- vault: target a specific vault by name when multiple are registered."] : [],
|
|
16295
16282
|
"",
|
|
16296
|
-
"
|
|
16297
|
-
"-
|
|
16298
|
-
"-
|
|
16299
|
-
"-
|
|
16283
|
+
"RESPONSE SHAPE (tree, depth = 2):",
|
|
16284
|
+
"- `results[]` \u2014 top-level direct note matches, ranked by query similarity.",
|
|
16285
|
+
" - `path`, `similarity` (query-similarity), `backlink_count`, `vault`",
|
|
16286
|
+
" - `matched_queries` (only when `query` is an array) \u2014 which of your queries hit this note",
|
|
16287
|
+
" - `blocks[]` \u2014 section-level matches WITHIN this note. Each block has `heading`, `lines: [start, end]`, `similarity` (query-similarity at block level).",
|
|
16288
|
+
" - `related[]` \u2014 expansion neighbours OF this note (deep mode only; empty otherwise). Each item has `path` and `expansion_similarity` (note-to-note, DIFFERENT SCALE from `similarity` \u2014 do not compare them numerically).",
|
|
16289
|
+
"- `truncated` \u2014 top-level, only when `query` is an array; true when merged candidates exceeded `limit`.",
|
|
16290
|
+
"",
|
|
16291
|
+
"INVARIANTS:",
|
|
16292
|
+
"- A `related` item NEVER has a `similarity` field \u2014 only `expansion_similarity`. A direct result NEVER has `expansion_similarity`. Don't conflate them.",
|
|
16293
|
+
"- The same neighbour can appear in `related[]` of multiple direct results (with different `expansion_similarity` values per parent) \u2014 that's by design.",
|
|
16294
|
+
"- `blocks[]` and `related[]` are always present on direct results (possibly empty).",
|
|
16295
|
+
"- After finding a relevant note, call `get_similar_notes` on it for a deeper neighbour profile \u2014 do not infer relationships from `related[]` alone.",
|
|
16300
16296
|
"",
|
|
16301
16297
|
"EXAMPLES:",
|
|
16302
16298
|
'- "where did I write about X?" \u2192 search_notes({query: "X"}) \u2014 quick.',
|
|
16303
16299
|
'- "what do I know about Y?" \u2192 search_notes({query: "Y", mode: "deep"}).',
|
|
16304
|
-
'- multilingual pair: search_notes({query: ["embeddings", "\u0432\u0435\u043A\u0442\u043E\u0440\u043D\u0438\u0439 \u043F\u043E\u0448\u0443\u043A"]})
|
|
16305
|
-
'- multilingual deep: search_notes({query: ["optimization", "\u043E\u043F\u0442\u0438\u043C\u0456\u0437\u0430\u0446\u0456\u044F"], mode: "deep"})
|
|
16300
|
+
'- multilingual pair: search_notes({query: ["embeddings", "\u0432\u0435\u043A\u0442\u043E\u0440\u043D\u0438\u0439 \u043F\u043E\u0448\u0443\u043A"]}).',
|
|
16301
|
+
'- multilingual deep: search_notes({query: ["optimization", "\u043E\u043F\u0442\u0438\u043C\u0456\u0437\u0430\u0446\u0456\u044F"], mode: "deep"}).',
|
|
16306
16302
|
"",
|
|
16307
16303
|
"PRE-FILTER (filter parameter):",
|
|
16308
16304
|
"- filter: optional structural narrowing applied BEFORE semantic ranking. Best when vault has many narrative notes that crowd top-K on a niche query.",
|
|
16309
16305
|
" Shape: { path_prefix?, exclude_path_prefix?, tags?, frontmatter? }. At least one field required.",
|
|
16310
16306
|
' - path_prefix: scope to a folder, or array of folders for OR-semantics (e.g. ["Tasks/", "Reflections/"]).',
|
|
16311
|
-
' - exclude_path_prefix: drop notes whose path starts with any of the listed prefixes (e.g. ["Resources/", "Archive/"]). Valid as the sole filter field
|
|
16307
|
+
' - exclude_path_prefix: drop notes whose path starts with any of the listed prefixes (e.g. ["Resources/", "Archive/"]). Valid as the sole filter field.',
|
|
16312
16308
|
' - tags: notes that have ANY of these tags (OR within the array; no leading "#").',
|
|
16313
16309
|
' - frontmatter: sift filter on frontmatter keys (e.g. { type: "reflection", status: "active" }). Same operator allow-list as query_notes.',
|
|
16314
|
-
" Composition: include \u2192 exclude \u2192 tags \u2192 frontmatter \u2192 threshold \u2192 semantic.
|
|
16315
|
-
'- scoped recall: search_notes({query: "trading lessons", filter: {tags: ["trading"]}})
|
|
16310
|
+
" Composition: include \u2192 exclude \u2192 tags \u2192 frontmatter \u2192 threshold \u2192 semantic.",
|
|
16311
|
+
'- scoped recall: search_notes({query: "trading lessons", filter: {tags: ["trading"]}}).',
|
|
16316
16312
|
'- carve out noise: search_notes({query: "active thinking", filter: {exclude_path_prefix: ["Resources/", "Archive/"]}, mode: "deep"}).',
|
|
16317
16313
|
'- scoped multi-query: search_notes({query: ["embeddings","\u0432\u0435\u043A\u0442\u043E\u0440\u043D\u0438\u0439 \u043F\u043E\u0448\u0443\u043A"], filter: {path_prefix: ["Resources/", "Inbox/"]}, mode: "deep"}).',
|
|
16318
16314
|
...registry2.isMulti() ? [
|
|
@@ -17613,12 +17609,12 @@ If the query is about a known folder, tag, or frontmatter dimension, pass \`filt
|
|
|
17613
17609
|
- Use \`limit\` to override the default note count in either mode. Widening \`limit\` widens recall.
|
|
17614
17610
|
|
|
17615
17611
|
### 3. Use the results
|
|
17616
|
-
- \`results\` \u2014 notes ranked by similarity
|
|
17617
|
-
- \`
|
|
17618
|
-
- \`
|
|
17619
|
-
- \`
|
|
17620
|
-
- \`
|
|
17621
|
-
- After finding a relevant note, call get_similar_notes
|
|
17612
|
+
- \`results\` \u2014 top-level notes ranked by similarity. Each result carries \`backlink_count\` (vault-wide inbound wikilinks + embeds) \u2014 useful as a tiebreaker when scores are close.
|
|
17613
|
+
- \`results[].blocks\` \u2014 section-level matches inside this note; use heading + line range to jump to the relevant part. Always present (possibly empty).
|
|
17614
|
+
- \`results[].related\` \u2014 expansion neighbours of this note (deep mode only). Each item has \`path\` and \`expansion_similarity\` \u2014 a DIFFERENT scale from \`similarity\`; do not compare them numerically. Always present (possibly empty). The same neighbour may appear under multiple parents.
|
|
17615
|
+
- \`matched_queries\` (only when \`query\` is an array) \u2014 which of your queries hit this note; lets you spot which synonym was load-bearing.
|
|
17616
|
+
- \`truncated\` (only when \`query\` is an array) \u2014 true when unique merged candidates exceeded \`limit\`; widen \`limit\` to see more.
|
|
17617
|
+
- After finding a relevant note, call \`get_similar_notes\` for a deeper neighbour profile.
|
|
17622
17618
|
|
|
17623
17619
|
## Routing between operations and semantic
|
|
17624
17620
|
|