rag-memory-epf-mcp 3.1.4 → 3.2.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.
Files changed (2) hide show
  1. package/dist/index.js +40 -30
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -83,18 +83,10 @@ class RAGKnowledgeGraphManager {
83
83
  console.error(`✅ ${EMBEDDING_MODEL} model loaded successfully (fp16)`);
84
84
  }
85
85
  catch (error) {
86
- console.error('❌ Failed to load embedding model (fp16):', error instanceof Error ? error.message : error);
87
- const FALLBACK_MODEL = 'Xenova/all-MiniLM-L6-v2';
88
- console.error(`🔄 Falling back to ${FALLBACK_MODEL}...`);
89
- try {
90
- this.embeddingModel = await pipeline('feature-extraction', FALLBACK_MODEL, { revision: 'main' });
91
- this.modelInitialized = true;
92
- console.error(`✅ ${FALLBACK_MODEL} loaded (fallback — 384-dim, English-focused)`);
93
- }
94
- catch (retryError) {
95
- console.error('❌ All embedding models failed to load. Search will not work.', retryError instanceof Error ? retryError.message : retryError);
96
- this.modelInitialized = false;
97
- }
86
+ console.error('❌ Failed to load embedding model:', error instanceof Error ? error.message : error);
87
+ console.error('⚠️ Semantic search will be unavailable. Other tools (CRUD, graph queries) still work.');
88
+ console.error('💡 Fix: Ensure ONNX model cache is accessible. Try: rm -rf ~/.npm/_onnx_models && restart.');
89
+ this.modelInitialized = false;
98
90
  }
99
91
  }
100
92
  async runMigrations() {
@@ -1353,11 +1345,14 @@ class RAGKnowledgeGraphManager {
1353
1345
  if (!document) {
1354
1346
  throw new Error(`Document with ID ${documentId} not found`);
1355
1347
  }
1356
- // Get chunks for this document
1348
+ // Get chunks for this document (with text for chunk-level matching)
1357
1349
  const chunks = this.db.prepare(`
1358
- SELECT rowid FROM chunk_metadata WHERE document_id = ?
1350
+ SELECT rowid, text FROM chunk_metadata WHERE document_id = ?
1359
1351
  `).all(documentId);
1360
1352
  let linkedCount = 0;
1353
+ const insertStmt = this.db.prepare(`
1354
+ INSERT OR IGNORE INTO chunk_entities (chunk_rowid, entity_id) VALUES (?, ?)
1355
+ `);
1361
1356
  for (const entityName of entityNames) {
1362
1357
  const entityId = `entity_${entityName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
1363
1358
  // Verify entity exists
@@ -1368,14 +1363,17 @@ class RAGKnowledgeGraphManager {
1368
1363
  console.warn(`Entity ${entityName} not found, skipping`);
1369
1364
  continue;
1370
1365
  }
1371
- // Link entity to all chunks of the document
1366
+ // Chunk-level filtering: only link to chunks where entity actually appears
1367
+ const nameMatcher = this.buildEntityMatcher(entityName);
1368
+ let entityLinked = false;
1372
1369
  for (const chunk of chunks) {
1373
- this.db.prepare(`
1374
- INSERT OR IGNORE INTO chunk_entities (chunk_rowid, entity_id)
1375
- VALUES (?, ?)
1376
- `).run(chunk.rowid, entityId);
1370
+ if (nameMatcher(chunk.text)) {
1371
+ insertStmt.run(chunk.rowid, entityId);
1372
+ entityLinked = true;
1373
+ }
1377
1374
  }
1378
- linkedCount++;
1375
+ if (entityLinked)
1376
+ linkedCount++;
1379
1377
  }
1380
1378
  console.error(`✅ Entities linked: ${linkedCount} entities linked to document`);
1381
1379
  return { documentId, linkedEntities: linkedCount };
@@ -1876,42 +1874,54 @@ class RAGKnowledgeGraphManager {
1876
1874
  chunkEntities = [relEntities.source_name, relEntities.target_name];
1877
1875
  }
1878
1876
  }
1879
- // Enhanced graph boost calculation
1877
+ // Enhanced graph boost calculation with decay + cap
1880
1878
  let graphBoost = 0;
1881
1879
  if (useGraph) {
1882
1880
  const queryEntities = this.extractTermsFromText(query);
1883
1881
  // Base boost for knowledge graph chunks
1884
1882
  if (result.chunk_type === 'entity') {
1885
- graphBoost += 0.15; // Entities are inherently valuable
1883
+ graphBoost += 0.15;
1886
1884
  }
1887
1885
  else if (result.chunk_type === 'relationship') {
1888
- graphBoost += 0.25; // Relationships show connections
1886
+ graphBoost += 0.25;
1889
1887
  }
1890
- // Additional boost for entity matches
1888
+ // Collect per-entity scores (instead of blind accumulation)
1889
+ const entityScores = [];
1891
1890
  const queryLower = query.toLowerCase();
1892
1891
  for (const entity of chunkEntities) {
1892
+ let score = 0;
1893
1893
  const entityLower = entity.toLowerCase();
1894
1894
  // Vector-matched entity (cross-lingual: "할랄 인증" → "KMF")
1895
1895
  if (queryMatchedEntities.has(entity)) {
1896
- graphBoost += 0.3;
1896
+ score = 0.3;
1897
1897
  }
1898
1898
  // Exact text match with extracted terms
1899
1899
  else if (queryEntities.some(qe => qe.toLowerCase() === entityLower)) {
1900
- graphBoost += 0.3;
1900
+ score = 0.3;
1901
1901
  }
1902
1902
  // Partial match: entity name appears in query or vice versa
1903
1903
  else if (queryLower.includes(entityLower) || entityLower.includes(queryLower)) {
1904
- graphBoost += 0.2;
1904
+ score = 0.2;
1905
1905
  }
1906
1906
  // Word-level partial match
1907
1907
  else if (entityLower.split(/\s+/).some(word => word.length >= 3 && queryLower.includes(word))) {
1908
- graphBoost += 0.15;
1908
+ score = 0.15;
1909
1909
  }
1910
- // Connected to a vector-matched entity
1910
+ // Connected to a vector-matched entity (additive, independent)
1911
1911
  if (connectedEntities.has(entity)) {
1912
- graphBoost += 0.15;
1912
+ score += 0.15;
1913
1913
  }
1914
+ if (score > 0)
1915
+ entityScores.push(score);
1916
+ }
1917
+ // Geometric decay: sort descending, apply 0.5^i decay per entity
1918
+ entityScores.sort((a, b) => b - a);
1919
+ let entityBoost = 0;
1920
+ for (let i = 0; i < entityScores.length; i++) {
1921
+ entityBoost += entityScores[i] * Math.pow(0.5, i);
1914
1922
  }
1923
+ // Hard cap to prevent graph domination
1924
+ graphBoost += Math.min(entityBoost, 0.4);
1915
1925
  }
1916
1926
  // Generate semantic summary
1917
1927
  const { summary, keyHighlight, relevanceScore } = await this.generateContentSummary(result.text, primaryQueryEmbedding, chunkEntities, result.chunk_type === 'relationship' ? 1 : 2 // Shorter summary for relationships
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rag-memory-epf-mcp",
3
- "version": "3.1.4",
3
+ "version": "3.2.0",
4
4
  "description": "MCP server for project-local RAG memory with knowledge graph and multilingual vector search",
5
5
  "license": "MIT",
6
6
  "author": "bripin123",