@ssmeo/mcp-local-rag 0.18.6
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/LICENSE +21 -0
- package/README.de.md +441 -0
- package/README.es.md +441 -0
- package/README.fr.md +441 -0
- package/README.md +530 -0
- package/README.pt-BR.md +441 -0
- package/README.zh-CN.md +441 -0
- package/dist/bin/install-skills.d.ts +19 -0
- package/dist/bin/install-skills.d.ts.map +1 -0
- package/dist/bin/install-skills.js +218 -0
- package/dist/bin/install-skills.js.map +1 -0
- package/dist/chunker/index.d.ts +24 -0
- package/dist/chunker/index.d.ts.map +1 -0
- package/dist/chunker/index.js +2 -0
- package/dist/chunker/index.js.map +1 -0
- package/dist/chunker/semantic-chunker.d.ts +96 -0
- package/dist/chunker/semantic-chunker.d.ts.map +1 -0
- package/dist/chunker/semantic-chunker.js +362 -0
- package/dist/chunker/semantic-chunker.js.map +1 -0
- package/dist/chunker/sentence-splitter.d.ts +32 -0
- package/dist/chunker/sentence-splitter.d.ts.map +1 -0
- package/dist/chunker/sentence-splitter.js +231 -0
- package/dist/chunker/sentence-splitter.js.map +1 -0
- package/dist/chunker/token-containment.d.ts +39 -0
- package/dist/chunker/token-containment.d.ts.map +1 -0
- package/dist/chunker/token-containment.js +83 -0
- package/dist/chunker/token-containment.js.map +1 -0
- package/dist/cli/common.d.ts +34 -0
- package/dist/cli/common.d.ts.map +1 -0
- package/dist/cli/common.js +121 -0
- package/dist/cli/common.js.map +1 -0
- package/dist/cli/delete.d.ts +3 -0
- package/dist/cli/delete.d.ts.map +1 -0
- package/dist/cli/delete.js +169 -0
- package/dist/cli/delete.js.map +1 -0
- package/dist/cli/file-collection.d.ts +2 -0
- package/dist/cli/file-collection.d.ts.map +1 -0
- package/dist/cli/file-collection.js +53 -0
- package/dist/cli/file-collection.js.map +1 -0
- package/dist/cli/ingest.d.ts +69 -0
- package/dist/cli/ingest.d.ts.map +1 -0
- package/dist/cli/ingest.js +323 -0
- package/dist/cli/ingest.js.map +1 -0
- package/dist/cli/list.d.ts +27 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +207 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/options.d.ts +89 -0
- package/dist/cli/options.d.ts.map +1 -0
- package/dist/cli/options.js +244 -0
- package/dist/cli/options.js.map +1 -0
- package/dist/cli/query.d.ts +17 -0
- package/dist/cli/query.d.ts.map +1 -0
- package/dist/cli/query.js +194 -0
- package/dist/cli/query.js.map +1 -0
- package/dist/cli/read-neighbors.d.ts +3 -0
- package/dist/cli/read-neighbors.d.ts.map +1 -0
- package/dist/cli/read-neighbors.js +192 -0
- package/dist/cli/read-neighbors.js.map +1 -0
- package/dist/cli/status.d.ts +6 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +78 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/sync.d.ts +6 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +271 -0
- package/dist/cli/sync.js.map +1 -0
- package/dist/cli-main.d.ts +9 -0
- package/dist/cli-main.d.ts.map +1 -0
- package/dist/cli-main.js +60 -0
- package/dist/cli-main.js.map +1 -0
- package/dist/embedder/index.d.ts +143 -0
- package/dist/embedder/index.d.ts.map +1 -0
- package/dist/embedder/index.js +429 -0
- package/dist/embedder/index.js.map +1 -0
- package/dist/embedder/remote.d.ts +51 -0
- package/dist/embedder/remote.d.ts.map +1 -0
- package/dist/embedder/remote.js +182 -0
- package/dist/embedder/remote.js.map +1 -0
- package/dist/features/list.d.ts +37 -0
- package/dist/features/list.d.ts.map +1 -0
- package/dist/features/list.js +41 -0
- package/dist/features/list.js.map +1 -0
- package/dist/features/sync.d.ts +219 -0
- package/dist/features/sync.d.ts.map +1 -0
- package/dist/features/sync.js +461 -0
- package/dist/features/sync.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/compute.d.ts +63 -0
- package/dist/ingest/compute.d.ts.map +1 -0
- package/dist/ingest/compute.js +161 -0
- package/dist/ingest/compute.js.map +1 -0
- package/dist/ingest/file.d.ts +40 -0
- package/dist/ingest/file.d.ts.map +1 -0
- package/dist/ingest/file.js +74 -0
- package/dist/ingest/file.js.map +1 -0
- package/dist/ingest/visual.d.ts +52 -0
- package/dist/ingest/visual.d.ts.map +1 -0
- package/dist/ingest/visual.js +294 -0
- package/dist/ingest/visual.js.map +1 -0
- package/dist/parser/docx-parser.d.ts +12 -0
- package/dist/parser/docx-parser.d.ts.map +1 -0
- package/dist/parser/docx-parser.js +375 -0
- package/dist/parser/docx-parser.js.map +1 -0
- package/dist/parser/html-parser.d.ts +16 -0
- package/dist/parser/html-parser.d.ts.map +1 -0
- package/dist/parser/html-parser.js +119 -0
- package/dist/parser/html-parser.js.map +1 -0
- package/dist/parser/index.d.ts +125 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +364 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/pdf-extract.d.ts +49 -0
- package/dist/parser/pdf-extract.d.ts.map +1 -0
- package/dist/parser/pdf-extract.js +114 -0
- package/dist/parser/pdf-extract.js.map +1 -0
- package/dist/parser/pdf-filter.d.ts +91 -0
- package/dist/parser/pdf-filter.d.ts.map +1 -0
- package/dist/parser/pdf-filter.js +522 -0
- package/dist/parser/pdf-filter.js.map +1 -0
- package/dist/parser/title-extractor.d.ts +28 -0
- package/dist/parser/title-extractor.d.ts.map +1 -0
- package/dist/parser/title-extractor.js +105 -0
- package/dist/parser/title-extractor.js.map +1 -0
- package/dist/pdf-visual/captioner.d.ts +11 -0
- package/dist/pdf-visual/captioner.d.ts.map +1 -0
- package/dist/pdf-visual/captioner.js +48 -0
- package/dist/pdf-visual/captioner.js.map +1 -0
- package/dist/pdf-visual/captioners/fast.d.ts +7 -0
- package/dist/pdf-visual/captioners/fast.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/fast.js +108 -0
- package/dist/pdf-visual/captioners/fast.js.map +1 -0
- package/dist/pdf-visual/captioners/quality.d.ts +7 -0
- package/dist/pdf-visual/captioners/quality.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/quality.js +101 -0
- package/dist/pdf-visual/captioners/quality.js.map +1 -0
- package/dist/pdf-visual/captioners/shared.d.ts +81 -0
- package/dist/pdf-visual/captioners/shared.d.ts.map +1 -0
- package/dist/pdf-visual/captioners/shared.js +156 -0
- package/dist/pdf-visual/captioners/shared.js.map +1 -0
- package/dist/pdf-visual/detector.d.ts +9 -0
- package/dist/pdf-visual/detector.d.ts.map +1 -0
- package/dist/pdf-visual/detector.js +269 -0
- package/dist/pdf-visual/detector.js.map +1 -0
- package/dist/pdf-visual/index.d.ts +13 -0
- package/dist/pdf-visual/index.d.ts.map +1 -0
- package/dist/pdf-visual/index.js +53 -0
- package/dist/pdf-visual/index.js.map +1 -0
- package/dist/pdf-visual/renderer.d.ts +9 -0
- package/dist/pdf-visual/renderer.d.ts.map +1 -0
- package/dist/pdf-visual/renderer.js +186 -0
- package/dist/pdf-visual/renderer.js.map +1 -0
- package/dist/pdf-visual/types.d.ts +53 -0
- package/dist/pdf-visual/types.d.ts.map +1 -0
- package/dist/pdf-visual/types.js +17 -0
- package/dist/pdf-visual/types.js.map +1 -0
- package/dist/server/error-utils.d.ts +63 -0
- package/dist/server/error-utils.d.ts.map +1 -0
- package/dist/server/error-utils.js +124 -0
- package/dist/server/error-utils.js.map +1 -0
- package/dist/server/index.d.ts +216 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +1068 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/list-scanner.d.ts +30 -0
- package/dist/server/list-scanner.d.ts.map +1 -0
- package/dist/server/list-scanner.js +50 -0
- package/dist/server/list-scanner.js.map +1 -0
- package/dist/server/tool-definitions.d.ts +8 -0
- package/dist/server/tool-definitions.d.ts.map +1 -0
- package/dist/server/tool-definitions.js +181 -0
- package/dist/server/tool-definitions.js.map +1 -0
- package/dist/server/tool-input.d.ts +37 -0
- package/dist/server/tool-input.d.ts.map +1 -0
- package/dist/server/tool-input.js +211 -0
- package/dist/server/tool-input.js.map +1 -0
- package/dist/server/types.d.ts +307 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +3 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server-main.d.ts +40 -0
- package/dist/server-main.d.ts.map +1 -0
- package/dist/server-main.js +254 -0
- package/dist/server-main.js.map +1 -0
- package/dist/utils/base-dirs.d.ts +145 -0
- package/dist/utils/base-dirs.d.ts.map +1 -0
- package/dist/utils/base-dirs.js +344 -0
- package/dist/utils/base-dirs.js.map +1 -0
- package/dist/utils/errors.d.ts +32 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +61 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/limits.d.ts +26 -0
- package/dist/utils/limits.d.ts.map +1 -0
- package/dist/utils/limits.js +28 -0
- package/dist/utils/limits.js.map +1 -0
- package/dist/utils/list-sources.d.ts +38 -0
- package/dist/utils/list-sources.d.ts.map +1 -0
- package/dist/utils/list-sources.js +40 -0
- package/dist/utils/list-sources.js.map +1 -0
- package/dist/utils/raw-data-utils.d.ts +76 -0
- package/dist/utils/raw-data-utils.d.ts.map +1 -0
- package/dist/utils/raw-data-utils.js +202 -0
- package/dist/utils/raw-data-utils.js.map +1 -0
- package/dist/utils/scan.d.ts +114 -0
- package/dist/utils/scan.d.ts.map +1 -0
- package/dist/utils/scan.js +209 -0
- package/dist/utils/scan.js.map +1 -0
- package/dist/utils/scope-match.d.ts +38 -0
- package/dist/utils/scope-match.d.ts.map +1 -0
- package/dist/utils/scope-match.js +86 -0
- package/dist/utils/scope-match.js.map +1 -0
- package/dist/utils/sensitive-path.d.ts +9 -0
- package/dist/utils/sensitive-path.d.ts.map +1 -0
- package/dist/utils/sensitive-path.js +78 -0
- package/dist/utils/sensitive-path.js.map +1 -0
- package/dist/utils/sync-path-key.d.ts +14 -0
- package/dist/utils/sync-path-key.d.ts.map +1 -0
- package/dist/utils/sync-path-key.js +27 -0
- package/dist/utils/sync-path-key.js.map +1 -0
- package/dist/utils/type-guards.d.ts +18 -0
- package/dist/utils/type-guards.d.ts.map +1 -0
- package/dist/utils/type-guards.js +34 -0
- package/dist/utils/type-guards.js.map +1 -0
- package/dist/utils/visual-profile.d.ts +10 -0
- package/dist/utils/visual-profile.d.ts.map +1 -0
- package/dist/utils/visual-profile.js +15 -0
- package/dist/utils/visual-profile.js.map +1 -0
- package/dist/vectordb/index.d.ts +132 -0
- package/dist/vectordb/index.d.ts.map +1 -0
- package/dist/vectordb/index.js +617 -0
- package/dist/vectordb/index.js.map +1 -0
- package/dist/vectordb/search-filters.d.ts +15 -0
- package/dist/vectordb/search-filters.d.ts.map +1 -0
- package/dist/vectordb/search-filters.js +129 -0
- package/dist/vectordb/search-filters.js.map +1 -0
- package/dist/vectordb/types.d.ts +194 -0
- package/dist/vectordb/types.d.ts.map +1 -0
- package/dist/vectordb/types.js +237 -0
- package/dist/vectordb/types.js.map +1 -0
- package/package.json +108 -0
- package/skills/mcp-local-rag/SKILL.md +234 -0
- package/skills/mcp-local-rag/references/cli-reference.md +190 -0
- package/skills/mcp-local-rag/references/html-ingestion.md +78 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-filters.d.ts","sourceRoot":"","sources":["../../src/vectordb/search-filters.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAS5D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,EAAE,CA+CzF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CA6BzF;AAiBD,2EAA2E;AAC3E,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;AAE/D,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,YAAY,EAAE,EAC7B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,MAAM,EAAE,MAAM,GACb,YAAY,EAAE,CAuChB"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Search filter functions extracted from VectorStore for testability
|
|
2
|
+
/**
|
|
3
|
+
* Standard deviation multiplier for detecting group boundaries.
|
|
4
|
+
* A gap is considered a "boundary" if it exceeds mean + k*std.
|
|
5
|
+
* Value of 1.5 means gaps > 1.5 standard deviations above mean are boundaries.
|
|
6
|
+
*/
|
|
7
|
+
const GROUPING_BOUNDARY_STD_MULTIPLIER = 1.5;
|
|
8
|
+
/**
|
|
9
|
+
* Cut the distance-sorted results at gaps wider than `mean + k*std`:
|
|
10
|
+
* `similar` keeps the first group, `related` up to two.
|
|
11
|
+
*/
|
|
12
|
+
export function applyGrouping(results, mode) {
|
|
13
|
+
if (results.length <= 1) {
|
|
14
|
+
return results;
|
|
15
|
+
}
|
|
16
|
+
// Calculate gaps between consecutive results with their indices
|
|
17
|
+
const gaps = [];
|
|
18
|
+
for (let i = 0; i < results.length - 1; i++) {
|
|
19
|
+
const current = results[i];
|
|
20
|
+
const next = results[i + 1];
|
|
21
|
+
if (current !== undefined && next !== undefined) {
|
|
22
|
+
gaps.push({ index: i + 1, gap: next.score - current.score });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (gaps.length === 0) {
|
|
26
|
+
return results;
|
|
27
|
+
}
|
|
28
|
+
// Calculate statistical threshold to identify significant gaps (group boundaries)
|
|
29
|
+
const gapValues = gaps.map((g) => g.gap);
|
|
30
|
+
const mean = gapValues.reduce((a, b) => a + b, 0) / gapValues.length;
|
|
31
|
+
const variance = gapValues.reduce((a, b) => a + (b - mean) ** 2, 0) / gapValues.length;
|
|
32
|
+
const std = Math.sqrt(variance);
|
|
33
|
+
const threshold = mean + GROUPING_BOUNDARY_STD_MULTIPLIER * std;
|
|
34
|
+
// Find all significant gaps (group boundaries)
|
|
35
|
+
const boundaries = gaps.filter((g) => g.gap > threshold).map((g) => g.index);
|
|
36
|
+
// If no boundaries found, return all results
|
|
37
|
+
if (boundaries.length === 0) {
|
|
38
|
+
return results;
|
|
39
|
+
}
|
|
40
|
+
// Determine how many groups to include based on mode
|
|
41
|
+
// 'similar': 1 group (cut at first boundary)
|
|
42
|
+
// 'related': 2 groups (cut at second boundary, or return all if only 1 boundary)
|
|
43
|
+
const groupsToInclude = mode === 'similar' ? 1 : 2;
|
|
44
|
+
const boundaryIndex = groupsToInclude - 1;
|
|
45
|
+
// If we don't have enough boundaries, return all results for 'related' mode
|
|
46
|
+
if (boundaryIndex >= boundaries.length) {
|
|
47
|
+
return mode === 'related' ? results : results.slice(0, boundaries[0]);
|
|
48
|
+
}
|
|
49
|
+
// Cut at the appropriate boundary
|
|
50
|
+
return results.slice(0, boundaries[boundaryIndex]);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Rank files by their best (lowest-distance) chunk and keep only the top
|
|
54
|
+
* `maxFiles` files' chunks.
|
|
55
|
+
*/
|
|
56
|
+
export function applyFileFilter(results, maxFiles) {
|
|
57
|
+
if (results.length === 0) {
|
|
58
|
+
return results;
|
|
59
|
+
}
|
|
60
|
+
// Find the best (lowest) score per file
|
|
61
|
+
const fileScores = new Map();
|
|
62
|
+
for (const result of results) {
|
|
63
|
+
const current = fileScores.get(result.filePath);
|
|
64
|
+
if (current === undefined || result.score < current) {
|
|
65
|
+
fileScores.set(result.filePath, result.score);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// If we have fewer or equal files than maxFiles, return all
|
|
69
|
+
if (fileScores.size <= maxFiles) {
|
|
70
|
+
return results;
|
|
71
|
+
}
|
|
72
|
+
// Sort files by best score (ascending) and take top N
|
|
73
|
+
const topFiles = new Set([...fileScores.entries()]
|
|
74
|
+
.sort((a, b) => a[1] - b[1])
|
|
75
|
+
.slice(0, maxFiles)
|
|
76
|
+
.map(([filePath]) => filePath));
|
|
77
|
+
// Filter results to only include chunks from top files
|
|
78
|
+
return results.filter((result) => topFiles.has(result.filePath));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Rerank by `distance / (1 + keyword_normalized * weight)`. Multiplicative, so
|
|
82
|
+
* a keyword match improves ranking without dominating semantic similarity and
|
|
83
|
+
* a document with no match keeps its original distance.
|
|
84
|
+
*/
|
|
85
|
+
/**
|
|
86
|
+
* BM25 score of one raw FTS row. A `_score` that is not a number scores 0, so
|
|
87
|
+
* the row keeps its vector distance instead of normalizing to `NaN`. `NaN` and
|
|
88
|
+
* `Infinity` ARE numbers and pass through unchanged.
|
|
89
|
+
*/
|
|
90
|
+
function readBm25Score(row) {
|
|
91
|
+
const score = row?.['_score'];
|
|
92
|
+
return typeof score === 'number' ? score : 0;
|
|
93
|
+
}
|
|
94
|
+
export function applyKeywordBoost(vectorResults, ftsResults, weight) {
|
|
95
|
+
// Build FTS score map with normalized scores (0-1)
|
|
96
|
+
let maxBm25Score = 0;
|
|
97
|
+
for (const result of ftsResults) {
|
|
98
|
+
const score = readBm25Score(result);
|
|
99
|
+
if (score > maxBm25Score) {
|
|
100
|
+
maxBm25Score = score;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const ftsScoreMap = new Map();
|
|
104
|
+
for (const result of ftsResults) {
|
|
105
|
+
if (!result) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const key = `${result['filePath']}:${result['chunkIndex']}`;
|
|
109
|
+
const rawScore = readBm25Score(result);
|
|
110
|
+
const normalized = maxBm25Score > 0 ? rawScore / maxBm25Score : 0;
|
|
111
|
+
ftsScoreMap.set(key, normalized);
|
|
112
|
+
}
|
|
113
|
+
// Apply multiplicative boost to vector results
|
|
114
|
+
const boostedResults = vectorResults.map((result) => {
|
|
115
|
+
const key = `${result.filePath}:${result.chunkIndex}`;
|
|
116
|
+
const keywordScore = ftsScoreMap.get(key) ?? 0;
|
|
117
|
+
// Multiplicative boost: distance / (1 + keyword * weight)
|
|
118
|
+
// - If keyword matches (score=1) and weight=1: distance halved
|
|
119
|
+
// - If no keyword match (score=0): distance unchanged
|
|
120
|
+
const boostedDistance = result.score / (1 + keywordScore * weight);
|
|
121
|
+
return {
|
|
122
|
+
...result,
|
|
123
|
+
score: boostedDistance,
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
// Re-sort by boosted distance (ascending = better)
|
|
127
|
+
return boostedResults.sort((a, b) => a.score - b.score);
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=search-filters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-filters.js","sourceRoot":"","sources":["../../src/vectordb/search-filters.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { AppError } from '../utils/errors.js';
|
|
2
|
+
/** Multiplier for candidate count in hybrid search (to allow reranking) */
|
|
3
|
+
export declare const HYBRID_SEARCH_CANDIDATE_MULTIPLIER = 2;
|
|
4
|
+
/** FTS index name (bump version when changing tokenizer settings) */
|
|
5
|
+
export declare const FTS_INDEX_NAME = "fts_index_v2";
|
|
6
|
+
/** Threshold for cleaning up old index versions (1 minute) */
|
|
7
|
+
export declare const FTS_CLEANUP_THRESHOLD_MS: number;
|
|
8
|
+
/** Default hybrid-search weight (vector vs FTS blend) when not configured */
|
|
9
|
+
export declare const DEFAULT_HYBRID_WEIGHT = 0.6;
|
|
10
|
+
/**
|
|
11
|
+
* Grouping mode for quality filtering
|
|
12
|
+
* - 'similar': Only return the most similar group (stops at first distance jump)
|
|
13
|
+
* - 'related': Include related groups (stops at second distance jump)
|
|
14
|
+
*/
|
|
15
|
+
export type GroupingMode = 'similar' | 'related';
|
|
16
|
+
/**
|
|
17
|
+
* VectorStore configuration
|
|
18
|
+
*/
|
|
19
|
+
export interface VectorStoreConfig {
|
|
20
|
+
/** LanceDB database path */
|
|
21
|
+
dbPath: string;
|
|
22
|
+
/** Table name */
|
|
23
|
+
tableName: string;
|
|
24
|
+
/** Maximum distance threshold for filtering results (optional) */
|
|
25
|
+
maxDistance?: number;
|
|
26
|
+
/** Grouping mode for quality filtering (optional) */
|
|
27
|
+
grouping?: GroupingMode;
|
|
28
|
+
/** Hybrid search weight for BM25 (0.0 = vector only, 1.0 = BM25 only, default 0.6) */
|
|
29
|
+
hybridWeight?: number;
|
|
30
|
+
/** Maximum number of files to keep in results (optional, filters by best score per file) */
|
|
31
|
+
maxFiles?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Per-call options for {@link VectorStore.search}, an object so a new option
|
|
35
|
+
* is not a breaking signature change.
|
|
36
|
+
*/
|
|
37
|
+
export interface SearchOptions {
|
|
38
|
+
/** Optional query text for keyword boost (BM25) */
|
|
39
|
+
queryText?: string;
|
|
40
|
+
/** Number of results to retrieve (default 10, valid range 1-20) */
|
|
41
|
+
limit?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Optional path-prefix scope (exact-or-descendant, prefixes unioned). Omitted
|
|
44
|
+
* = no prefilter (backward compatible).
|
|
45
|
+
*/
|
|
46
|
+
scope?: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Document metadata
|
|
50
|
+
*/
|
|
51
|
+
export interface DocumentMetadata {
|
|
52
|
+
/** File name */
|
|
53
|
+
fileName: string;
|
|
54
|
+
/** File size in bytes */
|
|
55
|
+
fileSize: number;
|
|
56
|
+
/** File type (extension) */
|
|
57
|
+
fileType: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validated, bounded image stored in a chunk's ordered attachment JSON.
|
|
61
|
+
*/
|
|
62
|
+
export interface VisualAttachment {
|
|
63
|
+
imageIndex: number;
|
|
64
|
+
mimeType: 'image/png' | 'image/jpeg';
|
|
65
|
+
data: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Vector chunk
|
|
69
|
+
*/
|
|
70
|
+
export interface VectorChunk {
|
|
71
|
+
/** Chunk ID (UUID) */
|
|
72
|
+
id: string;
|
|
73
|
+
/** File path (absolute) */
|
|
74
|
+
filePath: string;
|
|
75
|
+
/** Chunk index (zero-based) */
|
|
76
|
+
chunkIndex: number;
|
|
77
|
+
/** Chunk text */
|
|
78
|
+
text: string;
|
|
79
|
+
/** Embedding vector (dimension depends on model) */
|
|
80
|
+
vector: number[];
|
|
81
|
+
/** Metadata */
|
|
82
|
+
metadata: DocumentMetadata;
|
|
83
|
+
/** Document title extracted from file content (display-only, not used for scoring) */
|
|
84
|
+
fileTitle: string | null;
|
|
85
|
+
/** SHA-256 of the source file bytes; absent for chunks not ingested from a file. */
|
|
86
|
+
contentHash?: string;
|
|
87
|
+
/** Ordered `JSON.stringify(VisualAttachment[])`; omitted means no attachments. */
|
|
88
|
+
visualAttachments?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Requested visual-caption profile of the ingestion that wrote this row;
|
|
91
|
+
* omitted means normal text ingestion. Stored as a raw string: the store does
|
|
92
|
+
* not interpret the vocabulary, so an unknown value survives a backup.
|
|
93
|
+
*/
|
|
94
|
+
visualProfile?: string;
|
|
95
|
+
/** Ingestion timestamp (ISO 8601 format) */
|
|
96
|
+
timestamp: string;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Search result
|
|
100
|
+
*/
|
|
101
|
+
export interface SearchResult {
|
|
102
|
+
/** Stable persisted row identity used for attachment hydration. */
|
|
103
|
+
id: string;
|
|
104
|
+
/** File path */
|
|
105
|
+
filePath: string;
|
|
106
|
+
/** Chunk index */
|
|
107
|
+
chunkIndex: number;
|
|
108
|
+
/** Chunk text */
|
|
109
|
+
text: string;
|
|
110
|
+
/** Distance score using dot product (0 = identical, 1 = orthogonal, 2 = opposite) */
|
|
111
|
+
score: number;
|
|
112
|
+
/** Metadata */
|
|
113
|
+
metadata: DocumentMetadata;
|
|
114
|
+
/** Document title extracted from file content (display-only, not used for scoring) */
|
|
115
|
+
fileTitle: string | null;
|
|
116
|
+
}
|
|
117
|
+
/** Validated attachments for one persisted row, in visual order. */
|
|
118
|
+
export interface HydratedChunkAttachments {
|
|
119
|
+
id: string;
|
|
120
|
+
attachments: VisualAttachment[];
|
|
121
|
+
}
|
|
122
|
+
/** Result of one final-identity hydration query. */
|
|
123
|
+
export interface AttachmentHydrationResult {
|
|
124
|
+
rows: HydratedChunkAttachments[];
|
|
125
|
+
omittedCount: number;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Row from {@link VectorStore.getChunksByRange}. Distinct from `SearchResult`:
|
|
129
|
+
* no score (not ranked) and no metadata (not needed here).
|
|
130
|
+
*/
|
|
131
|
+
export interface ChunkRow {
|
|
132
|
+
/** File path (absolute) */
|
|
133
|
+
filePath: string;
|
|
134
|
+
/** Chunk index (zero-based) */
|
|
135
|
+
chunkIndex: number;
|
|
136
|
+
/** Chunk text */
|
|
137
|
+
text: string;
|
|
138
|
+
/** Document title extracted from file content (display-only, not used for scoring) */
|
|
139
|
+
fileTitle: string | null;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Raw result from LanceDB query (internal type)
|
|
143
|
+
*/
|
|
144
|
+
export interface LanceDBRawResult {
|
|
145
|
+
id: string;
|
|
146
|
+
filePath: string;
|
|
147
|
+
chunkIndex: number;
|
|
148
|
+
text: string;
|
|
149
|
+
metadata: DocumentMetadata;
|
|
150
|
+
/** Document title (optional - existing rows lack this field before migration) */
|
|
151
|
+
fileTitle?: string | null;
|
|
152
|
+
_distance?: number;
|
|
153
|
+
_score?: number;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Type guard for LanceDB raw search result
|
|
157
|
+
*/
|
|
158
|
+
export declare function isLanceDBRawResult(value: unknown): value is LanceDBRawResult;
|
|
159
|
+
/**
|
|
160
|
+
* Convert LanceDB raw result to SearchResult with type validation
|
|
161
|
+
* @throws DatabaseError if the result is invalid
|
|
162
|
+
*/
|
|
163
|
+
export declare function toSearchResult(raw: unknown): SearchResult;
|
|
164
|
+
/**
|
|
165
|
+
* Map a raw LanceDB row to a full {@link VectorChunk}, embedding included, so
|
|
166
|
+
* it round-trips back through `insertChunks` — unlike {@link toChunkRow} and
|
|
167
|
+
* {@link toSearchResult}, which drop the vector. LanceDB returns a typed array,
|
|
168
|
+
* normalized here to `number[]`.
|
|
169
|
+
*/
|
|
170
|
+
export declare function toVectorChunk(raw: unknown): VectorChunk;
|
|
171
|
+
/** Normalize only the defined legacy no-image sentinels; keep malformed JSON observable. */
|
|
172
|
+
export declare function normalizeVisualAttachments(value: unknown): string;
|
|
173
|
+
/** Parse one persisted attachment cell while keeping malformed siblings observable. */
|
|
174
|
+
export declare function parseHydratedVisualAttachments(value: unknown): {
|
|
175
|
+
attachments: VisualAttachment[];
|
|
176
|
+
omittedCount: number;
|
|
177
|
+
};
|
|
178
|
+
/**
|
|
179
|
+
* The minimal range-read shape: no score (not ranked) and no metadata (not
|
|
180
|
+
* needed for index-adjacent retrieval), so the shape check is narrower than
|
|
181
|
+
* {@link isLanceDBRawResult}. An empty or missing `fileTitle` reads as `null`.
|
|
182
|
+
*
|
|
183
|
+
* @throws DatabaseError when a required field is missing.
|
|
184
|
+
*/
|
|
185
|
+
export declare function toChunkRow(raw: unknown): ChunkRow;
|
|
186
|
+
/**
|
|
187
|
+
* Database error
|
|
188
|
+
*/
|
|
189
|
+
export declare class DatabaseError extends AppError {
|
|
190
|
+
constructor(message: string, options?: {
|
|
191
|
+
cause?: Error;
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/vectordb/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// VectorDB type definitions, constants, type guards, and error classes
|
|
2
|
+
import { AppError } from '../utils/errors.js';
|
|
3
|
+
import { MAX_VISUAL_RENDITION_BYTES } from '../utils/limits.js';
|
|
4
|
+
import { isInteger, isRecord } from '../utils/type-guards.js';
|
|
5
|
+
// ============================================
|
|
6
|
+
// Constants
|
|
7
|
+
// ============================================
|
|
8
|
+
/** Multiplier for candidate count in hybrid search (to allow reranking) */
|
|
9
|
+
export const HYBRID_SEARCH_CANDIDATE_MULTIPLIER = 2;
|
|
10
|
+
/** FTS index name (bump version when changing tokenizer settings) */
|
|
11
|
+
export const FTS_INDEX_NAME = 'fts_index_v2';
|
|
12
|
+
/** Threshold for cleaning up old index versions (1 minute) */
|
|
13
|
+
export const FTS_CLEANUP_THRESHOLD_MS = 60 * 1000;
|
|
14
|
+
/** Default hybrid-search weight (vector vs FTS blend) when not configured */
|
|
15
|
+
export const DEFAULT_HYBRID_WEIGHT = 0.6;
|
|
16
|
+
// ============================================
|
|
17
|
+
// Type Guards
|
|
18
|
+
// ============================================
|
|
19
|
+
/**
|
|
20
|
+
* Type guard for DocumentMetadata
|
|
21
|
+
*/
|
|
22
|
+
/** A non-null object with a numeric `length` — indices read as `unknown`. */
|
|
23
|
+
function isArrayLike(value) {
|
|
24
|
+
return isRecord(value) && typeof value['length'] === 'number';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A non-numeric element is rejected, never repaired: coercing, dropping, or
|
|
28
|
+
* padding it would change the vector's content or its dimension, and a
|
|
29
|
+
* corrupted embedding shows up only as quietly worse search results.
|
|
30
|
+
*/
|
|
31
|
+
function toEmbeddingVector(value) {
|
|
32
|
+
if (!isArrayLike(value)) {
|
|
33
|
+
throw new DatabaseError('Invalid chunk row shape from LanceDB (vector)');
|
|
34
|
+
}
|
|
35
|
+
const elements = Array.from(value);
|
|
36
|
+
const vector = [];
|
|
37
|
+
for (const element of elements) {
|
|
38
|
+
if (typeof element !== 'number') {
|
|
39
|
+
throw new DatabaseError('Invalid chunk row shape from LanceDB (non-numeric vector element)');
|
|
40
|
+
}
|
|
41
|
+
vector.push(element);
|
|
42
|
+
}
|
|
43
|
+
return vector;
|
|
44
|
+
}
|
|
45
|
+
function isDocumentMetadata(value) {
|
|
46
|
+
if (!isRecord(value)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return (typeof value['fileName'] === 'string' &&
|
|
50
|
+
typeof value['fileSize'] === 'number' &&
|
|
51
|
+
typeof value['fileType'] === 'string');
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Type guard for LanceDB raw search result
|
|
55
|
+
*/
|
|
56
|
+
export function isLanceDBRawResult(value) {
|
|
57
|
+
if (!isRecord(value)) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return (typeof value['id'] === 'string' &&
|
|
61
|
+
typeof value['filePath'] === 'string' &&
|
|
62
|
+
typeof value['chunkIndex'] === 'number' &&
|
|
63
|
+
typeof value['text'] === 'string' &&
|
|
64
|
+
isDocumentMetadata(value['metadata']));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Convert LanceDB raw result to SearchResult with type validation
|
|
68
|
+
* @throws DatabaseError if the result is invalid
|
|
69
|
+
*/
|
|
70
|
+
export function toSearchResult(raw) {
|
|
71
|
+
if (!isLanceDBRawResult(raw)) {
|
|
72
|
+
throw new DatabaseError('Invalid search result format from LanceDB');
|
|
73
|
+
}
|
|
74
|
+
// Vector rows carry `_distance`; `_score` is a defensive fallback for an
|
|
75
|
+
// FTS-shaped row reaching here (the live FTS path reads `_score` directly in
|
|
76
|
+
// applyKeywordBoost). The `?? 0` is unreachable in practice, and kept rather
|
|
77
|
+
// than throwing — a missing score is not worth failing a whole search over.
|
|
78
|
+
return {
|
|
79
|
+
id: raw.id,
|
|
80
|
+
filePath: raw.filePath,
|
|
81
|
+
chunkIndex: raw.chunkIndex,
|
|
82
|
+
text: raw.text,
|
|
83
|
+
score: raw._distance ?? raw._score ?? 0,
|
|
84
|
+
metadata: raw.metadata,
|
|
85
|
+
fileTitle: raw.fileTitle || null,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Map a raw LanceDB row to a full {@link VectorChunk}, embedding included, so
|
|
90
|
+
* it round-trips back through `insertChunks` — unlike {@link toChunkRow} and
|
|
91
|
+
* {@link toSearchResult}, which drop the vector. LanceDB returns a typed array,
|
|
92
|
+
* normalized here to `number[]`.
|
|
93
|
+
*/
|
|
94
|
+
export function toVectorChunk(raw) {
|
|
95
|
+
if (!isRecord(raw)) {
|
|
96
|
+
throw new DatabaseError('Invalid chunk row shape from LanceDB');
|
|
97
|
+
}
|
|
98
|
+
const { id, filePath, chunkIndex, text, vector, metadata, fileTitle, contentHash, visualAttachments, visualProfile, timestamp, } = raw;
|
|
99
|
+
if (typeof id !== 'string' ||
|
|
100
|
+
typeof filePath !== 'string' ||
|
|
101
|
+
typeof chunkIndex !== 'number' ||
|
|
102
|
+
typeof text !== 'string' ||
|
|
103
|
+
typeof timestamp !== 'string') {
|
|
104
|
+
throw new DatabaseError('Invalid chunk row shape from LanceDB (scalar fields)');
|
|
105
|
+
}
|
|
106
|
+
if (!isDocumentMetadata(metadata)) {
|
|
107
|
+
throw new DatabaseError('Invalid chunk row shape from LanceDB (metadata)');
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
id,
|
|
111
|
+
filePath,
|
|
112
|
+
chunkIndex,
|
|
113
|
+
text,
|
|
114
|
+
vector: toEmbeddingVector(vector),
|
|
115
|
+
metadata,
|
|
116
|
+
fileTitle: typeof fileTitle === 'string' && fileTitle.length > 0 ? fileTitle : null,
|
|
117
|
+
// Omit the key rather than store '' or undefined: the create path seeds ''
|
|
118
|
+
// for schema inference, and a '' that survived to a caller would read as a
|
|
119
|
+
// real hash equal to nothing on disk.
|
|
120
|
+
...(typeof contentHash === 'string' && contentHash.length > 0 ? { contentHash } : {}),
|
|
121
|
+
// Same absence rule as contentHash, applied to every legacy no-value form
|
|
122
|
+
// (missing column, NULL, create-path ''). Any other string is preserved
|
|
123
|
+
// verbatim so a backup taken here restores the row unchanged.
|
|
124
|
+
...(typeof visualProfile === 'string' && visualProfile.length > 0 ? { visualProfile } : {}),
|
|
125
|
+
visualAttachments: normalizeVisualAttachments(visualAttachments),
|
|
126
|
+
timestamp,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** Normalize only the defined legacy no-image sentinels; keep malformed JSON observable. */
|
|
130
|
+
export function normalizeVisualAttachments(value) {
|
|
131
|
+
return typeof value === 'string' && value.length > 0 ? value : '[]';
|
|
132
|
+
}
|
|
133
|
+
const VISUAL_RENDITION_MAX_BASE64_LENGTH = Math.ceil(MAX_VISUAL_RENDITION_BYTES / 3) * 4;
|
|
134
|
+
function decodeStrictBase64(value) {
|
|
135
|
+
if (typeof value !== 'string' ||
|
|
136
|
+
value.length === 0 ||
|
|
137
|
+
value.length > VISUAL_RENDITION_MAX_BASE64_LENGTH ||
|
|
138
|
+
value.length % 4 !== 0 ||
|
|
139
|
+
!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const decoded = Buffer.from(value, 'base64');
|
|
143
|
+
return decoded.toString('base64') === value ? decoded : null;
|
|
144
|
+
}
|
|
145
|
+
function isVisualAttachment(value) {
|
|
146
|
+
if (!isRecord(value)) {
|
|
147
|
+
return false;
|
|
148
|
+
}
|
|
149
|
+
const imageIndex = value['imageIndex'];
|
|
150
|
+
const mimeType = value['mimeType'];
|
|
151
|
+
if (!isInteger(imageIndex) ||
|
|
152
|
+
imageIndex < 0 ||
|
|
153
|
+
(mimeType !== 'image/png' && mimeType !== 'image/jpeg')) {
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
const bytes = decodeStrictBase64(value['data']);
|
|
157
|
+
if (!bytes || bytes.byteLength > MAX_VISUAL_RENDITION_BYTES) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return mimeType === 'image/png'
|
|
161
|
+
? bytes.length >= 8 &&
|
|
162
|
+
bytes[0] === 0x89 &&
|
|
163
|
+
bytes[1] === 0x50 &&
|
|
164
|
+
bytes[2] === 0x4e &&
|
|
165
|
+
bytes[3] === 0x47 &&
|
|
166
|
+
bytes[4] === 0x0d &&
|
|
167
|
+
bytes[5] === 0x0a &&
|
|
168
|
+
bytes[6] === 0x1a &&
|
|
169
|
+
bytes[7] === 0x0a
|
|
170
|
+
: bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;
|
|
171
|
+
}
|
|
172
|
+
/** Parse one persisted attachment cell while keeping malformed siblings observable. */
|
|
173
|
+
export function parseHydratedVisualAttachments(value) {
|
|
174
|
+
if (value === null || value === undefined || value === '' || value === '[]') {
|
|
175
|
+
return { attachments: [], omittedCount: 0 };
|
|
176
|
+
}
|
|
177
|
+
if (typeof value !== 'string') {
|
|
178
|
+
return { attachments: [], omittedCount: 1 };
|
|
179
|
+
}
|
|
180
|
+
let parsed;
|
|
181
|
+
try {
|
|
182
|
+
parsed = JSON.parse(value);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return { attachments: [], omittedCount: 1 };
|
|
186
|
+
}
|
|
187
|
+
if (!Array.isArray(parsed)) {
|
|
188
|
+
return { attachments: [], omittedCount: 1 };
|
|
189
|
+
}
|
|
190
|
+
const attachments = [];
|
|
191
|
+
let omittedCount = 0;
|
|
192
|
+
for (const item of parsed) {
|
|
193
|
+
if (!isVisualAttachment(item)) {
|
|
194
|
+
omittedCount += 1;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
attachments.push({
|
|
198
|
+
imageIndex: item.imageIndex,
|
|
199
|
+
mimeType: item.mimeType,
|
|
200
|
+
data: item.data,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
attachments.sort((left, right) => left.imageIndex - right.imageIndex);
|
|
204
|
+
return { attachments, omittedCount };
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* The minimal range-read shape: no score (not ranked) and no metadata (not
|
|
208
|
+
* needed for index-adjacent retrieval), so the shape check is narrower than
|
|
209
|
+
* {@link isLanceDBRawResult}. An empty or missing `fileTitle` reads as `null`.
|
|
210
|
+
*
|
|
211
|
+
* @throws DatabaseError when a required field is missing.
|
|
212
|
+
*/
|
|
213
|
+
export function toChunkRow(raw) {
|
|
214
|
+
if (!isRecord(raw)) {
|
|
215
|
+
throw new DatabaseError('Invalid chunk row shape from LanceDB');
|
|
216
|
+
}
|
|
217
|
+
const { filePath, chunkIndex, text } = raw;
|
|
218
|
+
if (typeof filePath !== 'string' || typeof chunkIndex !== 'number' || typeof text !== 'string') {
|
|
219
|
+
throw new DatabaseError('Invalid chunk row shape from LanceDB');
|
|
220
|
+
}
|
|
221
|
+
const rawFileTitle = raw['fileTitle'];
|
|
222
|
+
const fileTitle = typeof rawFileTitle === 'string' && rawFileTitle.length > 0 ? rawFileTitle : null;
|
|
223
|
+
return { filePath, chunkIndex, text, fileTitle };
|
|
224
|
+
}
|
|
225
|
+
// ============================================
|
|
226
|
+
// Error Classes
|
|
227
|
+
// ============================================
|
|
228
|
+
/**
|
|
229
|
+
* Database error
|
|
230
|
+
*/
|
|
231
|
+
export class DatabaseError extends AppError {
|
|
232
|
+
constructor(message, options) {
|
|
233
|
+
super(message, 'vectordb', 'internal', options);
|
|
234
|
+
this.name = 'DatabaseError';
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/vectordb/types.ts"],"names":[],"mappings":"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"}
|