@danielmarbach/mnemonic-mcp 0.25.5 → 0.26.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/CHANGELOG.md +23 -0
- package/README.md +2 -2
- package/build/cache.d.ts +8 -0
- package/build/cache.d.ts.map +1 -1
- package/build/cache.js +23 -0
- package/build/cache.js.map +1 -1
- package/build/index.js +78 -10
- package/build/index.js.map +1 -1
- package/build/lexical.d.ts +2 -2
- package/build/lexical.d.ts.map +1 -1
- package/build/lexical.js +6 -4
- package/build/lexical.js.map +1 -1
- package/build/recall.d.ts +39 -15
- package/build/recall.d.ts.map +1 -1
- package/build/recall.js +253 -25
- package/build/recall.js.map +1 -1
- package/build/semantic-patch.d.ts.map +1 -1
- package/build/semantic-patch.js +4 -1
- package/build/semantic-patch.js.map +1 -1
- package/package.json +1 -1
- package/skills/mnemonic-rpi-workflow/SKILL.md +21 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,29 @@ The format is loosely based on Keep a Changelog and uses semver-style version he
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.26.1] - 2026-04-26
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Improved `heading` selector error message to suggest `headingStartsWith` for prefix matching when exact headings are uncertain.
|
|
14
|
+
- `mnemonic-rpi-workflow` skill: added explicit handoff checkpoints between Research→Plan and Plan→Implement to prevent proceeding without user confirmation at natural workflow boundaries.
|
|
15
|
+
|
|
16
|
+
## [0.26.0] - 2026-04-25
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- Temporal recency boost: `recall` detects temporal intent in queries and applies an additive score nudge to newer notes for time-oriented searches.
|
|
21
|
+
- Confidence-gated temporal filtering: explicit time windows in queries trigger strict date filtering when confidence is high.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Project scope boost reduced from 0.15 to 0.03 so it acts as a tiebreaker rather than dominating fused rankings.
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- Graph-discovered candidates from relationship spreading now receive correct semantic ranks in the fused pipeline.
|
|
30
|
+
- Temporal filtering no longer silently drops notes with invalid dates.
|
|
31
|
+
|
|
9
32
|
## [0.25.5] - 2026-04-25
|
|
10
33
|
|
|
11
34
|
### Changed
|
package/README.md
CHANGED
|
@@ -352,9 +352,9 @@ Project identity derives from the **git remote URL**, normalized to a stable slu
|
|
|
352
352
|
|
|
353
353
|
### Recall
|
|
354
354
|
|
|
355
|
-
`recall` with `cwd` searches both vaults. Project notes get a
|
|
355
|
+
`recall` with `cwd` searches both vaults. Project notes get a **small tiebreaker boost** — a soft signal, not a hard filter — so global memories remain accessible while project context floats to the top.
|
|
356
356
|
|
|
357
|
-
**Hybrid recall** enhances semantic search with lightweight lexical reranking over note projections. When semantic results are weak, a bounded lexical rescue path scans projections for additional candidates, improving exact-match and identifier-heavy recall without changing the storage model or adding new infrastructure. **Canonical explanation promotion** boosts notes that explain key decisions and concepts for "why"-style questions, using structural signals like role, connections, and format rather than keyword matching.
|
|
357
|
+
**Hybrid recall** enhances semantic search with lightweight lexical reranking over note projections. When semantic results are weak, a bounded lexical rescue path scans projections for additional candidates, improving exact-match and identifier-heavy recall without changing the storage model or adding new infrastructure. **Canonical explanation promotion** boosts notes that explain key decisions and concepts for "why"-style questions, using structural signals like role, connections, and format rather than keyword matching. **Temporal recency:** when a query suggests temporal intent, newer notes receive an additive ranking nudge in default mode.
|
|
358
358
|
|
|
359
359
|
Recall modes:
|
|
360
360
|
|
package/build/cache.d.ts
CHANGED
|
@@ -13,12 +13,18 @@ interface SessionAccessRecord {
|
|
|
13
13
|
accessKind: "get" | "recall" | "summary";
|
|
14
14
|
score?: number;
|
|
15
15
|
}
|
|
16
|
+
interface ProjectionTokenCacheEntry {
|
|
17
|
+
projectionText: string;
|
|
18
|
+
tokens: string[];
|
|
19
|
+
}
|
|
16
20
|
export interface SessionProjectCache {
|
|
17
21
|
projectId: string;
|
|
18
22
|
/** Per-vault caches keyed by vaultPath. Built lazily per vault on first access. */
|
|
19
23
|
vaultCaches: Map<string, VaultCache>;
|
|
20
24
|
/** Projection cache shared across all cached vaults for this project. */
|
|
21
25
|
projectionsById: Map<string, NoteProjection>;
|
|
26
|
+
/** Tokenized projection text snapshots keyed by vaultPath::noteId. */
|
|
27
|
+
projectionTokensByKey: Map<string, ProjectionTokenCacheEntry>;
|
|
22
28
|
/** Recently inspected notes in the current MCP session. */
|
|
23
29
|
recentAccesses: SessionAccessRecord[];
|
|
24
30
|
/** Snapshots of recently inspected notes that survive cache invalidation. */
|
|
@@ -75,6 +81,8 @@ export declare function getRecentSessionAccessNote(projectId: string, vaultPath:
|
|
|
75
81
|
* No-op when no active cache exists for this project.
|
|
76
82
|
*/
|
|
77
83
|
export declare function setSessionCachedProjection(projectId: string, noteId: string, projection: NoteProjection): void;
|
|
84
|
+
export declare function getSessionCachedProjectionTokens(projectId: string, vaultPath: string, noteId: string, projectionText: string): string[] | undefined;
|
|
85
|
+
export declare function setSessionCachedProjectionTokens(projectId: string, vaultPath: string, noteId: string, projectionText: string, tokens: string[]): void;
|
|
78
86
|
export declare function recordSessionNoteAccess(projectId: string, vaultPath: string, noteId: string, accessKind: "get" | "recall" | "summary", score?: number): void;
|
|
79
87
|
export declare function getRecentSessionNoteAccesses(projectId: string): Array<{
|
|
80
88
|
noteId: string;
|
package/build/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC,UAAU,UAAU;IAClB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7B,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjB,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,UAAU,mBAAmB;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,yEAAyE;IACzE,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC7C,2DAA2D;IAC3D,cAAc,EAAE,mBAAmB,EAAE,CAAC;IACtC,6EAA6E;IAC7E,gBAAgB,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACpC,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/build/cache.js
CHANGED
|
@@ -18,6 +18,7 @@ function ensureActiveProjectCache(projectId) {
|
|
|
18
18
|
projectId,
|
|
19
19
|
vaultCaches: new Map(),
|
|
20
20
|
projectionsById: new Map(),
|
|
21
|
+
projectionTokensByKey: new Map(),
|
|
21
22
|
recentAccesses: [],
|
|
22
23
|
recentNotesByKey: new Map(),
|
|
23
24
|
lastBuiltAt: new Date().toISOString(),
|
|
@@ -39,6 +40,7 @@ export function invalidateActiveProjectCache() {
|
|
|
39
40
|
projectId: sessionCaches.activeProject.projectId,
|
|
40
41
|
vaultCaches: new Map(),
|
|
41
42
|
projectionsById: new Map(),
|
|
43
|
+
projectionTokensByKey: new Map(),
|
|
42
44
|
recentAccesses: sessionCaches.activeProject.recentAccesses,
|
|
43
45
|
recentNotesByKey: sessionCaches.activeProject.recentNotesByKey,
|
|
44
46
|
lastBuiltAt: new Date().toISOString(),
|
|
@@ -182,6 +184,27 @@ export function setSessionCachedProjection(projectId, noteId, projection) {
|
|
|
182
184
|
return;
|
|
183
185
|
cache.projectionsById.set(noteId, projection);
|
|
184
186
|
}
|
|
187
|
+
function projectionTokenKey(vaultPath, noteId) {
|
|
188
|
+
return `${vaultPath}::${noteId}`;
|
|
189
|
+
}
|
|
190
|
+
export function getSessionCachedProjectionTokens(projectId, vaultPath, noteId, projectionText) {
|
|
191
|
+
const cache = sessionCaches.activeProject;
|
|
192
|
+
if (!cache || cache.projectId !== projectId)
|
|
193
|
+
return undefined;
|
|
194
|
+
const cached = cache.projectionTokensByKey.get(projectionTokenKey(vaultPath, noteId));
|
|
195
|
+
if (!cached)
|
|
196
|
+
return undefined;
|
|
197
|
+
return cached.projectionText === projectionText ? cached.tokens : undefined;
|
|
198
|
+
}
|
|
199
|
+
export function setSessionCachedProjectionTokens(projectId, vaultPath, noteId, projectionText, tokens) {
|
|
200
|
+
const cache = sessionCaches.activeProject;
|
|
201
|
+
if (!cache || cache.projectId !== projectId)
|
|
202
|
+
return;
|
|
203
|
+
cache.projectionTokensByKey.set(projectionTokenKey(vaultPath, noteId), {
|
|
204
|
+
projectionText,
|
|
205
|
+
tokens,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
185
208
|
export function recordSessionNoteAccess(projectId, vaultPath, noteId, accessKind, score) {
|
|
186
209
|
const cache = ensureActiveProjectCache(projectId);
|
|
187
210
|
cache.recentAccesses = cache.recentAccesses
|
package/build/cache.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -10,12 +10,12 @@ import { embed, cosineSimilarity, embedModel } from "./embeddings.js";
|
|
|
10
10
|
import { buildTemporalHistoryEntry, computeConfidence, getNoteProvenance } from "./provenance.js";
|
|
11
11
|
import { enrichTemporalHistory } from "./temporal-interpretation.js";
|
|
12
12
|
import { getOrBuildProjection } from "./projections.js";
|
|
13
|
-
import { invalidateActiveProjectCache, getOrBuildVaultEmbeddings, getOrBuildVaultNoteList, getRecentSessionNoteAccesses, getRecentSessionAccessNote, getSessionCachedNote, getSessionCachedProjection, recordSessionNoteAccess, setSessionCachedNote, setSessionCachedProjection, } from "./cache.js";
|
|
13
|
+
import { invalidateActiveProjectCache, getOrBuildVaultEmbeddings, getOrBuildVaultNoteList, getRecentSessionNoteAccesses, getRecentSessionAccessNote, getSessionCachedNote, getSessionCachedProjection, getSessionCachedProjectionTokens, recordSessionNoteAccess, setSessionCachedNote, setSessionCachedProjection, setSessionCachedProjectionTokens, } from "./cache.js";
|
|
14
14
|
import { performance } from "perf_hooks";
|
|
15
15
|
import { filterRelationships, mergeRelationshipsFromNotes, normalizeMergePlanSourceIds, resolveEffectiveConsolidationMode, } from "./consolidate.js";
|
|
16
16
|
import { suggestAutoRelationships } from "./auto-relate.js";
|
|
17
|
-
import { computeRecallMetadataBoost, computeHybridScore, selectRecallResults, selectWorkflowResults, applyLexicalReranking, applyCanonicalExplanationPromotion, } from "./recall.js";
|
|
18
|
-
import { shouldTriggerLexicalRescue, rankDocumentsByTfIdf, LEXICAL_RESCUE_CANDIDATE_LIMIT, LEXICAL_RESCUE_THRESHOLD, LEXICAL_RESCUE_RESULT_LIMIT, } from "./lexical.js";
|
|
17
|
+
import { computeRecallMetadataBoost, computeHybridScore, selectRecallResults, selectWorkflowResults, applyLexicalReranking, enrichRescueCandidateScores, resolveDiscoveredVaults, applyCanonicalExplanationPromotion, applyGraphSpreadingActivation, assignDenseRanks, detectTemporalQueryHint, computeTemporalRecencyBoost, shouldApplyTemporalFiltering, isWithinTemporalFilterWindow, } from "./recall.js";
|
|
18
|
+
import { shouldTriggerLexicalRescue, prepareTfIdfCorpusFromTokenizedDocuments, rankDocumentsByTfIdf, LEXICAL_RESCUE_CANDIDATE_LIMIT, LEXICAL_RESCUE_THRESHOLD, LEXICAL_RESCUE_RESULT_LIMIT, tokenize, } from "./lexical.js";
|
|
19
19
|
import { getRelationshipPreview } from "./relationships.js";
|
|
20
20
|
import { MarkdownLintError, cleanMarkdown } from "./markdown.js";
|
|
21
21
|
import { applySemanticPatches } from "./semantic-patch.js";
|
|
@@ -286,6 +286,7 @@ const VAULT_PATH = process.env["VAULT_PATH"]
|
|
|
286
286
|
: defaultVaultPath();
|
|
287
287
|
const DEFAULT_RECALL_LIMIT = 5;
|
|
288
288
|
const DEFAULT_MIN_SIMILARITY = 0.3;
|
|
289
|
+
const PROJECT_SCOPE_BOOST = 0.03;
|
|
289
290
|
const TEMPORAL_HISTORY_NOTE_LIMIT = 5;
|
|
290
291
|
const TEMPORAL_HISTORY_COMMIT_LIMIT = 5;
|
|
291
292
|
async function readPackageVersion() {
|
|
@@ -1792,7 +1793,10 @@ function buildRecallCandidateContext(note) {
|
|
|
1792
1793
|
].reduce((sum, value) => sum + value, 0)),
|
|
1793
1794
|
};
|
|
1794
1795
|
}
|
|
1795
|
-
async function collectLexicalRescueCandidates(vaults, query, project, scope, tags, lifecycle, existingIds) {
|
|
1796
|
+
async function collectLexicalRescueCandidates(vaults, query, temporalQueryHint, project, scope, tags, lifecycle, existingIds) {
|
|
1797
|
+
const projectId = project?.id;
|
|
1798
|
+
const applyTemporalFilter = shouldApplyTemporalFiltering(temporalQueryHint);
|
|
1799
|
+
const temporalFilterWindowDays = applyTemporalFilter ? temporalQueryHint?.filterWindowDays : undefined;
|
|
1796
1800
|
const existingIdSet = new Set(existingIds.map((c) => c.id));
|
|
1797
1801
|
const rescuePool = [];
|
|
1798
1802
|
for (const vault of vaults) {
|
|
@@ -1813,6 +1817,11 @@ async function collectLexicalRescueCandidates(vaults, query, project, scope, tag
|
|
|
1813
1817
|
continue;
|
|
1814
1818
|
if (scope === "global" && isProjectNote)
|
|
1815
1819
|
continue;
|
|
1820
|
+
if (applyTemporalFilter
|
|
1821
|
+
&& temporalFilterWindowDays !== undefined
|
|
1822
|
+
&& !isWithinTemporalFilterWindow(note.updatedAt, temporalFilterWindowDays)) {
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1816
1825
|
const projection = await getOrBuildProjection(vault.storage, note).catch(() => undefined);
|
|
1817
1826
|
if (!projection)
|
|
1818
1827
|
continue;
|
|
@@ -1820,12 +1829,28 @@ async function collectLexicalRescueCandidates(vaults, query, project, scope, tag
|
|
|
1820
1829
|
id: note.id,
|
|
1821
1830
|
vault,
|
|
1822
1831
|
isCurrentProject: Boolean(isCurrentProject),
|
|
1832
|
+
updatedAt: note.updatedAt,
|
|
1823
1833
|
projectionText: projection.projectionText,
|
|
1834
|
+
projectionTokens: projectId
|
|
1835
|
+
? getSessionCachedProjectionTokens(projectId, vault.storage.vaultPath, note.id, projection.projectionText) ?? tokenize(projection.projectionText)
|
|
1836
|
+
: tokenize(projection.projectionText),
|
|
1824
1837
|
context: buildRecallCandidateContext(note),
|
|
1825
1838
|
});
|
|
1839
|
+
if (projectId) {
|
|
1840
|
+
setSessionCachedProjectionTokens(projectId, vault.storage.vaultPath, note.id, projection.projectionText, rescuePool[rescuePool.length - 1].projectionTokens);
|
|
1841
|
+
}
|
|
1826
1842
|
}
|
|
1827
1843
|
}
|
|
1828
|
-
const
|
|
1844
|
+
const rescueDocuments = rescuePool.map((candidate) => ({
|
|
1845
|
+
id: candidate.id,
|
|
1846
|
+
text: candidate.projectionText,
|
|
1847
|
+
}));
|
|
1848
|
+
const preparedRescueCorpus = prepareTfIdfCorpusFromTokenizedDocuments(rescuePool.map((candidate) => ({
|
|
1849
|
+
id: candidate.id,
|
|
1850
|
+
text: candidate.projectionText,
|
|
1851
|
+
tokens: candidate.projectionTokens,
|
|
1852
|
+
})));
|
|
1853
|
+
const rankedRescueIds = new Map(rankDocumentsByTfIdf(query, rescueDocuments, LEXICAL_RESCUE_CANDIDATE_LIMIT, preparedRescueCorpus).map((candidate) => [candidate.id, candidate.score]));
|
|
1829
1854
|
const candidates = [];
|
|
1830
1855
|
for (const candidate of rescuePool) {
|
|
1831
1856
|
const tfIdfScore = rankedRescueIds.get(candidate.id);
|
|
@@ -1834,7 +1859,10 @@ async function collectLexicalRescueCandidates(vaults, query, project, scope, tag
|
|
|
1834
1859
|
const lexicalScore = tfIdfScore;
|
|
1835
1860
|
if (lexicalScore < LEXICAL_RESCUE_THRESHOLD)
|
|
1836
1861
|
continue;
|
|
1837
|
-
const
|
|
1862
|
+
const temporalBoost = temporalQueryHint
|
|
1863
|
+
? computeTemporalRecencyBoost(candidate.updatedAt, temporalQueryHint)
|
|
1864
|
+
: 0;
|
|
1865
|
+
const boost = (candidate.isCurrentProject ? PROJECT_SCOPE_BOOST : 0) + candidate.context.metadataBoost + temporalBoost;
|
|
1838
1866
|
candidates.push({
|
|
1839
1867
|
id: candidate.id,
|
|
1840
1868
|
score: lexicalScore,
|
|
@@ -1851,7 +1879,7 @@ async function collectLexicalRescueCandidates(vaults, query, project, scope, tag
|
|
|
1851
1879
|
});
|
|
1852
1880
|
}
|
|
1853
1881
|
return candidates
|
|
1854
|
-
.sort((a, b) =>
|
|
1882
|
+
.sort((a, b) => (b.lexicalScore ?? 0) - (a.lexicalScore ?? 0))
|
|
1855
1883
|
.slice(0, LEXICAL_RESCUE_RESULT_LIMIT);
|
|
1856
1884
|
}
|
|
1857
1885
|
// ── recall ────────────────────────────────────────────────────────────────────
|
|
@@ -1929,6 +1957,9 @@ server.registerTool("recall", {
|
|
|
1929
1957
|
await embedMissingNotes(vault.storage).catch(() => { });
|
|
1930
1958
|
}
|
|
1931
1959
|
const scored = [];
|
|
1960
|
+
const temporalQueryHint = detectTemporalQueryHint(query);
|
|
1961
|
+
const applyTemporalFilter = shouldApplyTemporalFiltering(temporalQueryHint);
|
|
1962
|
+
const temporalFilterWindowDays = applyTemporalFilter ? temporalQueryHint?.filterWindowDays : undefined;
|
|
1932
1963
|
for (const vault of vaults) {
|
|
1933
1964
|
const embeddings = project
|
|
1934
1965
|
? (await getOrBuildVaultEmbeddings(project.id, vault)) ?? await vault.storage.listEmbeddings()
|
|
@@ -1958,8 +1989,16 @@ server.registerTool("recall", {
|
|
|
1958
1989
|
if (isProjectNote)
|
|
1959
1990
|
continue;
|
|
1960
1991
|
}
|
|
1992
|
+
if (applyTemporalFilter
|
|
1993
|
+
&& temporalFilterWindowDays !== undefined
|
|
1994
|
+
&& !isWithinTemporalFilterWindow(note.updatedAt, temporalFilterWindowDays)) {
|
|
1995
|
+
continue;
|
|
1996
|
+
}
|
|
1961
1997
|
const context = buildRecallCandidateContext(note);
|
|
1962
|
-
const
|
|
1998
|
+
const temporalBoost = temporalQueryHint
|
|
1999
|
+
? computeTemporalRecencyBoost(note.updatedAt, temporalQueryHint)
|
|
2000
|
+
: 0;
|
|
2001
|
+
const boost = (isCurrentProject ? PROJECT_SCOPE_BOOST : 0) + context.metadataBoost + temporalBoost;
|
|
1963
2002
|
scored.push({
|
|
1964
2003
|
id: rec.id,
|
|
1965
2004
|
score: rawScore,
|
|
@@ -1976,11 +2015,15 @@ server.registerTool("recall", {
|
|
|
1976
2015
|
}
|
|
1977
2016
|
}
|
|
1978
2017
|
const projectionTexts = new Map();
|
|
2018
|
+
const noteRelationships = new Map();
|
|
1979
2019
|
for (const candidate of scored) {
|
|
1980
2020
|
const note = await readCachedNote(candidate.vault, candidate.id).catch(() => null);
|
|
1981
2021
|
if (!note) {
|
|
1982
2022
|
continue;
|
|
1983
2023
|
}
|
|
2024
|
+
if (note.relatedTo && note.relatedTo.length > 0) {
|
|
2025
|
+
noteRelationships.set(candidate.id, note.relatedTo.map((r) => ({ id: r.id, type: r.type })));
|
|
2026
|
+
}
|
|
1984
2027
|
const projection = await getOrBuildProjection(candidate.vault.storage, note).catch(() => undefined);
|
|
1985
2028
|
if (!projection) {
|
|
1986
2029
|
continue;
|
|
@@ -2005,14 +2048,39 @@ server.registerTool("recall", {
|
|
|
2005
2048
|
};
|
|
2006
2049
|
const strongestSemanticScore = scored.reduce((max, candidate) => max === undefined ? candidate.score : Math.max(max, candidate.score), undefined);
|
|
2007
2050
|
const reranked = applyLexicalReranking(scored, query, getProjectionText);
|
|
2008
|
-
|
|
2051
|
+
// Apply graph spreading activation: traverse related notes and boost their scores
|
|
2052
|
+
const preSpreadIds = new Set(reranked.map((c) => c.id));
|
|
2053
|
+
const getNoteRelationships = (id) => {
|
|
2054
|
+
return noteRelationships.get(id);
|
|
2055
|
+
};
|
|
2056
|
+
const withGraphSpread = applyGraphSpreadingActivation(reranked, getNoteRelationships);
|
|
2057
|
+
// Resolve correct vault for graph-discovered candidates that inherited their
|
|
2058
|
+
// entry point's vault instead of their own.
|
|
2059
|
+
await resolveDiscoveredVaults(withGraphSpread, preSpreadIds, async (id) => {
|
|
2060
|
+
for (const v of vaults) {
|
|
2061
|
+
const note = await v.storage.readNote(id).catch(() => null);
|
|
2062
|
+
if (note) {
|
|
2063
|
+
const isCurrentProject = project ? note.project === project.id : false;
|
|
2064
|
+
return { vault: v, isCurrentProject };
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
return undefined;
|
|
2068
|
+
});
|
|
2069
|
+
// Re-assign semanticRank after graph spreading since scores are now modified
|
|
2070
|
+
// and graph-discovered candidates have no semanticRank.
|
|
2071
|
+
const sortedByScore = [...withGraphSpread].sort((a, b) => b.score - a.score || b.boosted - a.boosted);
|
|
2072
|
+
assignDenseRanks(sortedByScore, (candidate) => candidate.score, (candidate, rank) => {
|
|
2073
|
+
candidate.semanticRank = rank;
|
|
2074
|
+
});
|
|
2075
|
+
let promoted = applyCanonicalExplanationPromotion(withGraphSpread);
|
|
2009
2076
|
// Lexical rescue: when semantic results are weak, scan projections for additional candidates.
|
|
2010
2077
|
// Skip rescue when the caller set a strict minSimilarity above the default,
|
|
2011
2078
|
// because rescue candidates lack genuine semantic backing.
|
|
2012
2079
|
const rescueAllowed = minSimilarity <= DEFAULT_MIN_SIMILARITY;
|
|
2013
2080
|
if (rescueAllowed && shouldTriggerLexicalRescue(strongestSemanticScore, scored.length)) {
|
|
2014
|
-
const rescueCandidates = await collectLexicalRescueCandidates(vaults, query, project ?? undefined, scope, tags, lifecycle, promoted);
|
|
2081
|
+
const rescueCandidates = await collectLexicalRescueCandidates(vaults, query, temporalQueryHint, project ?? undefined, scope, tags, lifecycle, promoted);
|
|
2015
2082
|
promoted.push(...rescueCandidates);
|
|
2083
|
+
enrichRescueCandidateScores(promoted, query, getProjectionText);
|
|
2016
2084
|
promoted = applyCanonicalExplanationPromotion(promoted);
|
|
2017
2085
|
}
|
|
2018
2086
|
const top = mode === "workflow"
|