rag-memory-epf-mcp 3.1.5 → 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.
- package/dist/index.js +36 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1345,11 +1345,14 @@ class RAGKnowledgeGraphManager {
|
|
|
1345
1345
|
if (!document) {
|
|
1346
1346
|
throw new Error(`Document with ID ${documentId} not found`);
|
|
1347
1347
|
}
|
|
1348
|
-
// Get chunks for this document
|
|
1348
|
+
// Get chunks for this document (with text for chunk-level matching)
|
|
1349
1349
|
const chunks = this.db.prepare(`
|
|
1350
|
-
SELECT rowid FROM chunk_metadata WHERE document_id = ?
|
|
1350
|
+
SELECT rowid, text FROM chunk_metadata WHERE document_id = ?
|
|
1351
1351
|
`).all(documentId);
|
|
1352
1352
|
let linkedCount = 0;
|
|
1353
|
+
const insertStmt = this.db.prepare(`
|
|
1354
|
+
INSERT OR IGNORE INTO chunk_entities (chunk_rowid, entity_id) VALUES (?, ?)
|
|
1355
|
+
`);
|
|
1353
1356
|
for (const entityName of entityNames) {
|
|
1354
1357
|
const entityId = `entity_${entityName.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
|
|
1355
1358
|
// Verify entity exists
|
|
@@ -1360,14 +1363,17 @@ class RAGKnowledgeGraphManager {
|
|
|
1360
1363
|
console.warn(`Entity ${entityName} not found, skipping`);
|
|
1361
1364
|
continue;
|
|
1362
1365
|
}
|
|
1363
|
-
//
|
|
1366
|
+
// Chunk-level filtering: only link to chunks where entity actually appears
|
|
1367
|
+
const nameMatcher = this.buildEntityMatcher(entityName);
|
|
1368
|
+
let entityLinked = false;
|
|
1364
1369
|
for (const chunk of chunks) {
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1370
|
+
if (nameMatcher(chunk.text)) {
|
|
1371
|
+
insertStmt.run(chunk.rowid, entityId);
|
|
1372
|
+
entityLinked = true;
|
|
1373
|
+
}
|
|
1369
1374
|
}
|
|
1370
|
-
|
|
1375
|
+
if (entityLinked)
|
|
1376
|
+
linkedCount++;
|
|
1371
1377
|
}
|
|
1372
1378
|
console.error(`✅ Entities linked: ${linkedCount} entities linked to document`);
|
|
1373
1379
|
return { documentId, linkedEntities: linkedCount };
|
|
@@ -1868,42 +1874,54 @@ class RAGKnowledgeGraphManager {
|
|
|
1868
1874
|
chunkEntities = [relEntities.source_name, relEntities.target_name];
|
|
1869
1875
|
}
|
|
1870
1876
|
}
|
|
1871
|
-
// Enhanced graph boost calculation
|
|
1877
|
+
// Enhanced graph boost calculation with decay + cap
|
|
1872
1878
|
let graphBoost = 0;
|
|
1873
1879
|
if (useGraph) {
|
|
1874
1880
|
const queryEntities = this.extractTermsFromText(query);
|
|
1875
1881
|
// Base boost for knowledge graph chunks
|
|
1876
1882
|
if (result.chunk_type === 'entity') {
|
|
1877
|
-
graphBoost += 0.15;
|
|
1883
|
+
graphBoost += 0.15;
|
|
1878
1884
|
}
|
|
1879
1885
|
else if (result.chunk_type === 'relationship') {
|
|
1880
|
-
graphBoost += 0.25;
|
|
1886
|
+
graphBoost += 0.25;
|
|
1881
1887
|
}
|
|
1882
|
-
//
|
|
1888
|
+
// Collect per-entity scores (instead of blind accumulation)
|
|
1889
|
+
const entityScores = [];
|
|
1883
1890
|
const queryLower = query.toLowerCase();
|
|
1884
1891
|
for (const entity of chunkEntities) {
|
|
1892
|
+
let score = 0;
|
|
1885
1893
|
const entityLower = entity.toLowerCase();
|
|
1886
1894
|
// Vector-matched entity (cross-lingual: "할랄 인증" → "KMF")
|
|
1887
1895
|
if (queryMatchedEntities.has(entity)) {
|
|
1888
|
-
|
|
1896
|
+
score = 0.3;
|
|
1889
1897
|
}
|
|
1890
1898
|
// Exact text match with extracted terms
|
|
1891
1899
|
else if (queryEntities.some(qe => qe.toLowerCase() === entityLower)) {
|
|
1892
|
-
|
|
1900
|
+
score = 0.3;
|
|
1893
1901
|
}
|
|
1894
1902
|
// Partial match: entity name appears in query or vice versa
|
|
1895
1903
|
else if (queryLower.includes(entityLower) || entityLower.includes(queryLower)) {
|
|
1896
|
-
|
|
1904
|
+
score = 0.2;
|
|
1897
1905
|
}
|
|
1898
1906
|
// Word-level partial match
|
|
1899
1907
|
else if (entityLower.split(/\s+/).some(word => word.length >= 3 && queryLower.includes(word))) {
|
|
1900
|
-
|
|
1908
|
+
score = 0.15;
|
|
1901
1909
|
}
|
|
1902
|
-
// Connected to a vector-matched entity
|
|
1910
|
+
// Connected to a vector-matched entity (additive, independent)
|
|
1903
1911
|
if (connectedEntities.has(entity)) {
|
|
1904
|
-
|
|
1912
|
+
score += 0.15;
|
|
1905
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);
|
|
1906
1922
|
}
|
|
1923
|
+
// Hard cap to prevent graph domination
|
|
1924
|
+
graphBoost += Math.min(entityBoost, 0.4);
|
|
1907
1925
|
}
|
|
1908
1926
|
// Generate semantic summary
|
|
1909
1927
|
const { summary, keyHighlight, relevanceScore } = await this.generateContentSummary(result.text, primaryQueryEmbedding, chunkEntities, result.chunk_type === 'relationship' ? 1 : 2 // Shorter summary for relationships
|