@velvetmonkey/flywheel-memory 2.5.13 → 2.5.14

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.
Files changed (2) hide show
  1. package/dist/index.js +24 -6
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -4304,10 +4304,26 @@ async function suggestRelatedLinks(content, options = {}) {
4304
4304
  (token) => contentTokens.has(token) || contentStems.has(stem(token))
4305
4305
  );
4306
4306
  const strongCooccurrence = boost >= config2.minCooccurrenceGate;
4307
- if (!hasContentOverlap && !strongCooccurrence) {
4307
+ let multiSeedOK = true;
4308
+ if (!hasContentOverlap && cooccurrenceIndex && config2.minContentMatch > 0) {
4309
+ let qualifyingSeedCount = 0;
4310
+ for (const seed of cooccurrenceSeeds) {
4311
+ const entityAssocs = cooccurrenceIndex.associations[seed];
4312
+ if (!entityAssocs) continue;
4313
+ const coocCount = entityAssocs.get(entityName) || 0;
4314
+ if (coocCount < (cooccurrenceIndex.minCount ?? 2)) continue;
4315
+ const dfEntity = cooccurrenceIndex.documentFrequency?.get(entityName) || 0;
4316
+ const dfSeed = cooccurrenceIndex.documentFrequency?.get(seed) || 0;
4317
+ if (dfEntity === 0 || dfSeed === 0) continue;
4318
+ const npmi = computeNpmi(coocCount, dfEntity, dfSeed, cooccurrenceIndex.totalNotesScanned ?? 1);
4319
+ if (npmi > 0) qualifyingSeedCount++;
4320
+ }
4321
+ multiSeedOK = qualifyingSeedCount >= 2;
4322
+ }
4323
+ if (!hasContentOverlap && !(strongCooccurrence && multiSeedOK)) {
4308
4324
  continue;
4309
4325
  }
4310
- if (hasContentOverlap || strongCooccurrence) {
4326
+ if (hasContentOverlap || strongCooccurrence && multiSeedOK) {
4311
4327
  entitiesWithAnyScoringPath.add(entityName);
4312
4328
  }
4313
4329
  const typeBoost = disabled.has("type_boost") ? 0 : getTypeBoost(category, getConfig()?.custom_categories, entityName);
@@ -4853,8 +4869,8 @@ var init_wikilinks = __esm({
4853
4869
  minWordLength: 3,
4854
4870
  minSuggestionScore: 10,
4855
4871
  // Exact match (10) or two stem matches
4856
- minMatchRatio: 0.4,
4857
- // 40% of multi-word entity must match
4872
+ minMatchRatio: 0.6,
4873
+ // 60% of multi-word entity must match (blocks 1-of-2 token FPs)
4858
4874
  requireMultipleMatches: false,
4859
4875
  stemMatchBonus: 5,
4860
4876
  // Standard bonus for stem matches
@@ -4863,8 +4879,10 @@ var init_wikilinks = __esm({
4863
4879
  fuzzyMatchBonus: 4,
4864
4880
  // Moderate fuzzy bonus
4865
4881
  contentRelevanceFloor: 5,
4866
- noRelevanceCap: 10,
4867
- minCooccurrenceGate: 5,
4882
+ noRelevanceCap: 9,
4883
+ // Below minSuggestionScore — graph-only entities can't reach threshold
4884
+ minCooccurrenceGate: 6,
4885
+ // Stronger graph signal for graph-only admission
4868
4886
  minContentMatch: 2
4869
4887
  },
4870
4888
  aggressive: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velvetmonkey/flywheel-memory",
3
- "version": "2.5.13",
3
+ "version": "2.5.14",
4
4
  "description": "MCP tools that search, write, and auto-link your Obsidian vault — and learn from your edits.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -56,7 +56,7 @@
56
56
  "dependencies": {
57
57
  "@huggingface/transformers": "^3.8.1",
58
58
  "@modelcontextprotocol/sdk": "^1.26.0",
59
- "@velvetmonkey/vault-core": "^2.5.13",
59
+ "@velvetmonkey/vault-core": "^2.5.14",
60
60
  "better-sqlite3": "^12.0.0",
61
61
  "chokidar": "^4.0.0",
62
62
  "gray-matter": "^4.0.3",