abb-opencode-local-rag 0.1.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 (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.de.md +416 -0
  3. package/README.es.md +416 -0
  4. package/README.fr.md +416 -0
  5. package/README.md +491 -0
  6. package/README.pt-BR.md +416 -0
  7. package/README.zh-CN.md +416 -0
  8. package/dist/bin/install-skills.d.ts +20 -0
  9. package/dist/bin/install-skills.d.ts.map +1 -0
  10. package/dist/bin/install-skills.js +195 -0
  11. package/dist/bin/install-skills.js.map +1 -0
  12. package/dist/chunker/index.d.ts +24 -0
  13. package/dist/chunker/index.d.ts.map +1 -0
  14. package/dist/chunker/index.js +2 -0
  15. package/dist/chunker/index.js.map +1 -0
  16. package/dist/chunker/semantic-chunker.d.ts +97 -0
  17. package/dist/chunker/semantic-chunker.d.ts.map +1 -0
  18. package/dist/chunker/semantic-chunker.js +294 -0
  19. package/dist/chunker/semantic-chunker.js.map +1 -0
  20. package/dist/chunker/sentence-splitter.d.ts +28 -0
  21. package/dist/chunker/sentence-splitter.d.ts.map +1 -0
  22. package/dist/chunker/sentence-splitter.js +219 -0
  23. package/dist/chunker/sentence-splitter.js.map +1 -0
  24. package/dist/cli/common.d.ts +65 -0
  25. package/dist/cli/common.d.ts.map +1 -0
  26. package/dist/cli/common.js +138 -0
  27. package/dist/cli/common.js.map +1 -0
  28. package/dist/cli/delete.d.ts +8 -0
  29. package/dist/cli/delete.d.ts.map +1 -0
  30. package/dist/cli/delete.js +173 -0
  31. package/dist/cli/delete.js.map +1 -0
  32. package/dist/cli/file-collection.d.ts +2 -0
  33. package/dist/cli/file-collection.d.ts.map +1 -0
  34. package/dist/cli/file-collection.js +53 -0
  35. package/dist/cli/file-collection.js.map +1 -0
  36. package/dist/cli/ingest.d.ts +100 -0
  37. package/dist/cli/ingest.d.ts.map +1 -0
  38. package/dist/cli/ingest.js +363 -0
  39. package/dist/cli/ingest.js.map +1 -0
  40. package/dist/cli/list.d.ts +35 -0
  41. package/dist/cli/list.d.ts.map +1 -0
  42. package/dist/cli/list.js +210 -0
  43. package/dist/cli/list.js.map +1 -0
  44. package/dist/cli/options.d.ts +100 -0
  45. package/dist/cli/options.d.ts.map +1 -0
  46. package/dist/cli/options.js +241 -0
  47. package/dist/cli/options.js.map +1 -0
  48. package/dist/cli/query.d.ts +24 -0
  49. package/dist/cli/query.d.ts.map +1 -0
  50. package/dist/cli/query.js +191 -0
  51. package/dist/cli/query.js.map +1 -0
  52. package/dist/cli/read-neighbors.d.ts +11 -0
  53. package/dist/cli/read-neighbors.d.ts.map +1 -0
  54. package/dist/cli/read-neighbors.js +224 -0
  55. package/dist/cli/read-neighbors.js.map +1 -0
  56. package/dist/cli/status.d.ts +8 -0
  57. package/dist/cli/status.d.ts.map +1 -0
  58. package/dist/cli/status.js +80 -0
  59. package/dist/cli/status.js.map +1 -0
  60. package/dist/cli/sync.d.ts +8 -0
  61. package/dist/cli/sync.d.ts.map +1 -0
  62. package/dist/cli/sync.js +244 -0
  63. package/dist/cli/sync.js.map +1 -0
  64. package/dist/cli-main.d.ts +12 -0
  65. package/dist/cli-main.d.ts.map +1 -0
  66. package/dist/cli-main.js +63 -0
  67. package/dist/cli-main.js.map +1 -0
  68. package/dist/embedder/index.d.ts +85 -0
  69. package/dist/embedder/index.d.ts.map +1 -0
  70. package/dist/embedder/index.js +284 -0
  71. package/dist/embedder/index.js.map +1 -0
  72. package/dist/features/list.d.ts +37 -0
  73. package/dist/features/list.d.ts.map +1 -0
  74. package/dist/features/list.js +40 -0
  75. package/dist/features/list.js.map +1 -0
  76. package/dist/features/sync.d.ts +207 -0
  77. package/dist/features/sync.d.ts.map +1 -0
  78. package/dist/features/sync.js +380 -0
  79. package/dist/features/sync.js.map +1 -0
  80. package/dist/index.d.ts +3 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +53 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/ingest/compute.d.ts +86 -0
  85. package/dist/ingest/compute.d.ts.map +1 -0
  86. package/dist/ingest/compute.js +177 -0
  87. package/dist/ingest/compute.js.map +1 -0
  88. package/dist/ingest/file.d.ts +27 -0
  89. package/dist/ingest/file.d.ts.map +1 -0
  90. package/dist/ingest/file.js +67 -0
  91. package/dist/ingest/file.js.map +1 -0
  92. package/dist/ingest/visual.d.ts +45 -0
  93. package/dist/ingest/visual.d.ts.map +1 -0
  94. package/dist/ingest/visual.js +234 -0
  95. package/dist/ingest/visual.js.map +1 -0
  96. package/dist/parser/docx-parser.d.ts +12 -0
  97. package/dist/parser/docx-parser.d.ts.map +1 -0
  98. package/dist/parser/docx-parser.js +328 -0
  99. package/dist/parser/docx-parser.js.map +1 -0
  100. package/dist/parser/html-parser.d.ts +18 -0
  101. package/dist/parser/html-parser.d.ts.map +1 -0
  102. package/dist/parser/html-parser.js +102 -0
  103. package/dist/parser/html-parser.js.map +1 -0
  104. package/dist/parser/index.d.ts +214 -0
  105. package/dist/parser/index.d.ts.map +1 -0
  106. package/dist/parser/index.js +454 -0
  107. package/dist/parser/index.js.map +1 -0
  108. package/dist/parser/pdf-extract.d.ts +81 -0
  109. package/dist/parser/pdf-extract.d.ts.map +1 -0
  110. package/dist/parser/pdf-extract.js +112 -0
  111. package/dist/parser/pdf-extract.js.map +1 -0
  112. package/dist/parser/pdf-filter.d.ts +117 -0
  113. package/dist/parser/pdf-filter.d.ts.map +1 -0
  114. package/dist/parser/pdf-filter.js +528 -0
  115. package/dist/parser/pdf-filter.js.map +1 -0
  116. package/dist/parser/title-extractor.d.ts +69 -0
  117. package/dist/parser/title-extractor.d.ts.map +1 -0
  118. package/dist/parser/title-extractor.js +145 -0
  119. package/dist/parser/title-extractor.js.map +1 -0
  120. package/dist/pdf-visual/captioner.d.ts +16 -0
  121. package/dist/pdf-visual/captioner.d.ts.map +1 -0
  122. package/dist/pdf-visual/captioner.js +63 -0
  123. package/dist/pdf-visual/captioner.js.map +1 -0
  124. package/dist/pdf-visual/captioners/fast.d.ts +7 -0
  125. package/dist/pdf-visual/captioners/fast.d.ts.map +1 -0
  126. package/dist/pdf-visual/captioners/fast.js +103 -0
  127. package/dist/pdf-visual/captioners/fast.js.map +1 -0
  128. package/dist/pdf-visual/captioners/quality.d.ts +7 -0
  129. package/dist/pdf-visual/captioners/quality.d.ts.map +1 -0
  130. package/dist/pdf-visual/captioners/quality.js +127 -0
  131. package/dist/pdf-visual/captioners/quality.js.map +1 -0
  132. package/dist/pdf-visual/captioners/shared.d.ts +44 -0
  133. package/dist/pdf-visual/captioners/shared.d.ts.map +1 -0
  134. package/dist/pdf-visual/captioners/shared.js +104 -0
  135. package/dist/pdf-visual/captioners/shared.js.map +1 -0
  136. package/dist/pdf-visual/detector.d.ts +9 -0
  137. package/dist/pdf-visual/detector.d.ts.map +1 -0
  138. package/dist/pdf-visual/detector.js +234 -0
  139. package/dist/pdf-visual/detector.js.map +1 -0
  140. package/dist/pdf-visual/index.d.ts +13 -0
  141. package/dist/pdf-visual/index.d.ts.map +1 -0
  142. package/dist/pdf-visual/index.js +45 -0
  143. package/dist/pdf-visual/index.js.map +1 -0
  144. package/dist/pdf-visual/renderer.d.ts +9 -0
  145. package/dist/pdf-visual/renderer.d.ts.map +1 -0
  146. package/dist/pdf-visual/renderer.js +177 -0
  147. package/dist/pdf-visual/renderer.js.map +1 -0
  148. package/dist/pdf-visual/types.d.ts +62 -0
  149. package/dist/pdf-visual/types.d.ts.map +1 -0
  150. package/dist/pdf-visual/types.js +32 -0
  151. package/dist/pdf-visual/types.js.map +1 -0
  152. package/dist/server/error-utils.d.ts +79 -0
  153. package/dist/server/error-utils.d.ts.map +1 -0
  154. package/dist/server/error-utils.js +148 -0
  155. package/dist/server/error-utils.js.map +1 -0
  156. package/dist/server/index.d.ts +258 -0
  157. package/dist/server/index.d.ts.map +1 -0
  158. package/dist/server/index.js +1104 -0
  159. package/dist/server/index.js.map +1 -0
  160. package/dist/server/list-scanner.d.ts +52 -0
  161. package/dist/server/list-scanner.d.ts.map +1 -0
  162. package/dist/server/list-scanner.js +72 -0
  163. package/dist/server/list-scanner.js.map +1 -0
  164. package/dist/server/tool-definitions.d.ts +8 -0
  165. package/dist/server/tool-definitions.d.ts.map +1 -0
  166. package/dist/server/tool-definitions.js +181 -0
  167. package/dist/server/tool-definitions.js.map +1 -0
  168. package/dist/server/tool-input.d.ts +37 -0
  169. package/dist/server/tool-input.d.ts.map +1 -0
  170. package/dist/server/tool-input.js +216 -0
  171. package/dist/server/tool-input.js.map +1 -0
  172. package/dist/server/types.d.ts +331 -0
  173. package/dist/server/types.d.ts.map +1 -0
  174. package/dist/server/types.js +3 -0
  175. package/dist/server/types.js.map +1 -0
  176. package/dist/server-main.d.ts +46 -0
  177. package/dist/server-main.d.ts.map +1 -0
  178. package/dist/server-main.js +242 -0
  179. package/dist/server-main.js.map +1 -0
  180. package/dist/utils/base-dirs.d.ts +212 -0
  181. package/dist/utils/base-dirs.d.ts.map +1 -0
  182. package/dist/utils/base-dirs.js +422 -0
  183. package/dist/utils/base-dirs.js.map +1 -0
  184. package/dist/utils/errors.d.ts +24 -0
  185. package/dist/utils/errors.d.ts.map +1 -0
  186. package/dist/utils/errors.js +53 -0
  187. package/dist/utils/errors.js.map +1 -0
  188. package/dist/utils/limits.d.ts +26 -0
  189. package/dist/utils/limits.d.ts.map +1 -0
  190. package/dist/utils/limits.js +28 -0
  191. package/dist/utils/limits.js.map +1 -0
  192. package/dist/utils/list-sources.d.ts +47 -0
  193. package/dist/utils/list-sources.d.ts.map +1 -0
  194. package/dist/utils/list-sources.js +50 -0
  195. package/dist/utils/list-sources.js.map +1 -0
  196. package/dist/utils/raw-data-utils.d.ts +131 -0
  197. package/dist/utils/raw-data-utils.d.ts.map +1 -0
  198. package/dist/utils/raw-data-utils.js +255 -0
  199. package/dist/utils/raw-data-utils.js.map +1 -0
  200. package/dist/utils/scan.d.ts +126 -0
  201. package/dist/utils/scan.d.ts.map +1 -0
  202. package/dist/utils/scan.js +221 -0
  203. package/dist/utils/scan.js.map +1 -0
  204. package/dist/utils/scope-match.d.ts +43 -0
  205. package/dist/utils/scope-match.d.ts.map +1 -0
  206. package/dist/utils/scope-match.js +87 -0
  207. package/dist/utils/scope-match.js.map +1 -0
  208. package/dist/utils/sensitive-path.d.ts +23 -0
  209. package/dist/utils/sensitive-path.d.ts.map +1 -0
  210. package/dist/utils/sensitive-path.js +91 -0
  211. package/dist/utils/sensitive-path.js.map +1 -0
  212. package/dist/utils/sync-path-key.d.ts +20 -0
  213. package/dist/utils/sync-path-key.d.ts.map +1 -0
  214. package/dist/utils/sync-path-key.js +33 -0
  215. package/dist/utils/sync-path-key.js.map +1 -0
  216. package/dist/vectordb/index.d.ts +168 -0
  217. package/dist/vectordb/index.d.ts.map +1 -0
  218. package/dist/vectordb/index.js +619 -0
  219. package/dist/vectordb/index.js.map +1 -0
  220. package/dist/vectordb/search-filters.d.ts +39 -0
  221. package/dist/vectordb/search-filters.d.ts.map +1 -0
  222. package/dist/vectordb/search-filters.js +136 -0
  223. package/dist/vectordb/search-filters.js.map +1 -0
  224. package/dist/vectordb/types.d.ts +196 -0
  225. package/dist/vectordb/types.d.ts.map +1 -0
  226. package/dist/vectordb/types.js +224 -0
  227. package/dist/vectordb/types.js.map +1 -0
  228. package/package.json +105 -0
  229. package/skills/mcp-local-rag/SKILL.md +308 -0
  230. package/skills/mcp-local-rag/references/cli-reference.md +175 -0
  231. package/skills/mcp-local-rag/references/html-ingestion.md +78 -0
  232. package/skills/mcp-local-rag/references/query-optimization.md +57 -0
  233. package/skills/mcp-local-rag/references/result-refinement.md +56 -0
@@ -0,0 +1,39 @@
1
+ import type { GroupingMode, SearchResult } from './types.js';
2
+ /**
3
+ * Apply grouping algorithm to filter results by detecting group boundaries.
4
+ *
5
+ * Uses statistical threshold (mean + k*std) to identify significant gaps (group boundaries).
6
+ * - 'similar': Returns only the first group (cuts at first boundary)
7
+ * - 'related': Returns up to 2 groups (cuts at second boundary)
8
+ *
9
+ * @param results - Search results sorted by distance (ascending)
10
+ * @param mode - Grouping mode ('similar' = 1 group, 'related' = 2 groups)
11
+ * @returns Filtered results
12
+ */
13
+ export declare function applyGrouping(results: SearchResult[], mode: GroupingMode): SearchResult[];
14
+ /**
15
+ * Apply file-based filter to limit results to chunks from the top N files.
16
+ *
17
+ * Ranks files by their best (lowest distance) chunk score and keeps only
18
+ * chunks belonging to the top `maxFiles` files.
19
+ *
20
+ * @param results - Search results sorted by distance (ascending)
21
+ * @param maxFiles - Maximum number of files to keep
22
+ * @returns Filtered results preserving original order
23
+ */
24
+ export declare function applyFileFilter(results: SearchResult[], maxFiles: number): SearchResult[];
25
+ /**
26
+ * Apply keyword boost to rerank vector search results
27
+ * Uses multiplicative formula: final_distance = distance / (1 + keyword_normalized * weight)
28
+ *
29
+ * This proportional boost ensures:
30
+ * - Keyword matches improve ranking without dominating semantic similarity
31
+ * - Documents without keyword matches keep their original vector distance
32
+ * - Higher weight = stronger influence of keyword matching
33
+ *
34
+ * @param vectorResults - Results from vector search (already filtered by maxDistance/grouping)
35
+ * @param ftsResults - Raw FTS results with BM25 scores
36
+ * @param weight - Boost weight (0-1, from hybridWeight config)
37
+ */
38
+ export declare function applyKeywordBoost(vectorResults: SearchResult[], ftsResults: Record<string, unknown>[], weight: number): SearchResult[];
39
+ //# sourceMappingURL=search-filters.d.ts.map
@@ -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;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,EAAE,CAyCzF;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAyBzF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,aAAa,EAAE,YAAY,EAAE,EAC7B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EACrC,MAAM,EAAE,MAAM,GACb,YAAY,EAAE,CAoChB"}
@@ -0,0 +1,136 @@
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
+ * Apply grouping algorithm to filter results by detecting group boundaries.
10
+ *
11
+ * Uses statistical threshold (mean + k*std) to identify significant gaps (group boundaries).
12
+ * - 'similar': Returns only the first group (cuts at first boundary)
13
+ * - 'related': Returns up to 2 groups (cuts at second boundary)
14
+ *
15
+ * @param results - Search results sorted by distance (ascending)
16
+ * @param mode - Grouping mode ('similar' = 1 group, 'related' = 2 groups)
17
+ * @returns Filtered results
18
+ */
19
+ export function applyGrouping(results, mode) {
20
+ if (results.length <= 1)
21
+ return results;
22
+ // Calculate gaps between consecutive results with their indices
23
+ const gaps = [];
24
+ for (let i = 0; i < results.length - 1; i++) {
25
+ const current = results[i];
26
+ const next = results[i + 1];
27
+ if (current !== undefined && next !== undefined) {
28
+ gaps.push({ index: i + 1, gap: next.score - current.score });
29
+ }
30
+ }
31
+ if (gaps.length === 0)
32
+ return results;
33
+ // Calculate statistical threshold to identify significant gaps (group boundaries)
34
+ const gapValues = gaps.map((g) => g.gap);
35
+ const mean = gapValues.reduce((a, b) => a + b, 0) / gapValues.length;
36
+ const variance = gapValues.reduce((a, b) => a + (b - mean) ** 2, 0) / gapValues.length;
37
+ const std = Math.sqrt(variance);
38
+ const threshold = mean + GROUPING_BOUNDARY_STD_MULTIPLIER * std;
39
+ // Find all significant gaps (group boundaries)
40
+ const boundaries = gaps.filter((g) => g.gap > threshold).map((g) => g.index);
41
+ // If no boundaries found, return all results
42
+ if (boundaries.length === 0)
43
+ return results;
44
+ // Determine how many groups to include based on mode
45
+ // 'similar': 1 group (cut at first boundary)
46
+ // 'related': 2 groups (cut at second boundary, or return all if only 1 boundary)
47
+ const groupsToInclude = mode === 'similar' ? 1 : 2;
48
+ const boundaryIndex = groupsToInclude - 1;
49
+ // If we don't have enough boundaries, return all results for 'related' mode
50
+ if (boundaryIndex >= boundaries.length) {
51
+ return mode === 'related' ? results : results.slice(0, boundaries[0]);
52
+ }
53
+ // Cut at the appropriate boundary
54
+ return results.slice(0, boundaries[boundaryIndex]);
55
+ }
56
+ /**
57
+ * Apply file-based filter to limit results to chunks from the top N files.
58
+ *
59
+ * Ranks files by their best (lowest distance) chunk score and keeps only
60
+ * chunks belonging to the top `maxFiles` files.
61
+ *
62
+ * @param results - Search results sorted by distance (ascending)
63
+ * @param maxFiles - Maximum number of files to keep
64
+ * @returns Filtered results preserving original order
65
+ */
66
+ export function applyFileFilter(results, maxFiles) {
67
+ if (results.length === 0)
68
+ return results;
69
+ // Find the best (lowest) score per file
70
+ const fileScores = new Map();
71
+ for (const result of results) {
72
+ const current = fileScores.get(result.filePath);
73
+ if (current === undefined || result.score < current) {
74
+ fileScores.set(result.filePath, result.score);
75
+ }
76
+ }
77
+ // If we have fewer or equal files than maxFiles, return all
78
+ if (fileScores.size <= maxFiles)
79
+ return results;
80
+ // Sort files by best score (ascending) and take top N
81
+ const topFiles = new Set([...fileScores.entries()]
82
+ .sort((a, b) => a[1] - b[1])
83
+ .slice(0, maxFiles)
84
+ .map(([filePath]) => filePath));
85
+ // Filter results to only include chunks from top files
86
+ return results.filter((result) => topFiles.has(result.filePath));
87
+ }
88
+ /**
89
+ * Apply keyword boost to rerank vector search results
90
+ * Uses multiplicative formula: final_distance = distance / (1 + keyword_normalized * weight)
91
+ *
92
+ * This proportional boost ensures:
93
+ * - Keyword matches improve ranking without dominating semantic similarity
94
+ * - Documents without keyword matches keep their original vector distance
95
+ * - Higher weight = stronger influence of keyword matching
96
+ *
97
+ * @param vectorResults - Results from vector search (already filtered by maxDistance/grouping)
98
+ * @param ftsResults - Raw FTS results with BM25 scores
99
+ * @param weight - Boost weight (0-1, from hybridWeight config)
100
+ */
101
+ export function applyKeywordBoost(vectorResults, ftsResults, weight) {
102
+ // Build FTS score map with normalized scores (0-1)
103
+ let maxBm25Score = 0;
104
+ for (const result of ftsResults) {
105
+ if (!result)
106
+ continue;
107
+ const score = result['_score'] ?? 0;
108
+ if (score > maxBm25Score)
109
+ maxBm25Score = score;
110
+ }
111
+ const ftsScoreMap = new Map();
112
+ for (const result of ftsResults) {
113
+ if (!result)
114
+ continue;
115
+ const key = `${result['filePath']}:${result['chunkIndex']}`;
116
+ const rawScore = result['_score'] ?? 0;
117
+ const normalized = maxBm25Score > 0 ? rawScore / maxBm25Score : 0;
118
+ ftsScoreMap.set(key, normalized);
119
+ }
120
+ // Apply multiplicative boost to vector results
121
+ const boostedResults = vectorResults.map((result) => {
122
+ const key = `${result.filePath}:${result.chunkIndex}`;
123
+ const keywordScore = ftsScoreMap.get(key) ?? 0;
124
+ // Multiplicative boost: distance / (1 + keyword * weight)
125
+ // - If keyword matches (score=1) and weight=1: distance halved
126
+ // - If no keyword match (score=0): distance unchanged
127
+ const boostedDistance = result.score / (1 + keywordScore * weight);
128
+ return {
129
+ ...result,
130
+ score: boostedDistance,
131
+ };
132
+ });
133
+ // Re-sort by boosted distance (ascending = better)
134
+ return boostedResults.sort((a, b) => a.score - b.score);
135
+ }
136
+ //# 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,196 @@
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}.
35
+ * Grouped into an object (instead of positional params) so the caller can pass
36
+ * any subset and so adding options (like `scope`) is not a breaking signature
37
+ * change.
38
+ */
39
+ export interface SearchOptions {
40
+ /** Optional query text for keyword boost (BM25) */
41
+ queryText?: string;
42
+ /** Number of results to retrieve (default 10, valid range 1-20) */
43
+ limit?: number;
44
+ /**
45
+ * Optional path-prefix scope (exact-or-descendant, prefixes unioned). Omitted
46
+ * = no prefilter (backward compatible).
47
+ */
48
+ scope?: string[];
49
+ }
50
+ /**
51
+ * Document metadata
52
+ */
53
+ export interface DocumentMetadata {
54
+ /** File name */
55
+ fileName: string;
56
+ /** File size in bytes */
57
+ fileSize: number;
58
+ /** File type (extension) */
59
+ fileType: string;
60
+ }
61
+ /**
62
+ * Validated, bounded image stored in a chunk's ordered attachment JSON.
63
+ */
64
+ export interface VisualAttachment {
65
+ imageIndex: number;
66
+ mimeType: 'image/png' | 'image/jpeg';
67
+ data: string;
68
+ }
69
+ /**
70
+ * Vector chunk
71
+ */
72
+ export interface VectorChunk {
73
+ /** Chunk ID (UUID) */
74
+ id: string;
75
+ /** File path (absolute) */
76
+ filePath: string;
77
+ /** Chunk index (zero-based) */
78
+ chunkIndex: number;
79
+ /** Chunk text */
80
+ text: string;
81
+ /** Embedding vector (dimension depends on model) */
82
+ vector: number[];
83
+ /** Metadata */
84
+ metadata: DocumentMetadata;
85
+ /** Document title extracted from file content (display-only, not used for scoring) */
86
+ fileTitle: string | null;
87
+ /** SHA-256 of the source file bytes; absent for chunks not ingested from a file. */
88
+ contentHash?: string;
89
+ /** Ordered `JSON.stringify(VisualAttachment[])`; omitted means no attachments. */
90
+ visualAttachments?: string;
91
+ /** Ingestion timestamp (ISO 8601 format) */
92
+ timestamp: string;
93
+ }
94
+ /**
95
+ * Search result
96
+ */
97
+ export interface SearchResult {
98
+ /** Stable persisted row identity used for attachment hydration. */
99
+ id: string;
100
+ /** File path */
101
+ filePath: string;
102
+ /** Chunk index */
103
+ chunkIndex: number;
104
+ /** Chunk text */
105
+ text: string;
106
+ /** Distance score using dot product (0 = identical, 1 = orthogonal, 2 = opposite) */
107
+ score: number;
108
+ /** Metadata */
109
+ metadata: DocumentMetadata;
110
+ /** Document title extracted from file content (display-only, not used for scoring) */
111
+ fileTitle: string | null;
112
+ }
113
+ /** Validated attachments for one persisted row, in visual order. */
114
+ export interface HydratedChunkAttachments {
115
+ id: string;
116
+ attachments: VisualAttachment[];
117
+ }
118
+ /** Result of one final-identity hydration query. */
119
+ export interface AttachmentHydrationResult {
120
+ rows: HydratedChunkAttachments[];
121
+ omittedCount: number;
122
+ }
123
+ /**
124
+ * Row returned by VectorStore.getChunksByRange.
125
+ * Distinct from SearchResult: no score (not a ranked result) and no metadata
126
+ * (not needed for index-adjacent retrieval). Consumed by
127
+ * handleReadChunkNeighbors and runReadNeighbors.
128
+ */
129
+ export interface ChunkRow {
130
+ /** File path (absolute) */
131
+ filePath: string;
132
+ /** Chunk index (zero-based) */
133
+ chunkIndex: number;
134
+ /** Chunk text */
135
+ text: string;
136
+ /** Document title extracted from file content (display-only, not used for scoring) */
137
+ fileTitle: string | null;
138
+ }
139
+ /**
140
+ * Raw result from LanceDB query (internal type)
141
+ */
142
+ export interface LanceDBRawResult {
143
+ id: string;
144
+ filePath: string;
145
+ chunkIndex: number;
146
+ text: string;
147
+ metadata: DocumentMetadata;
148
+ /** Document title (optional - existing rows lack this field before migration) */
149
+ fileTitle?: string | null;
150
+ _distance?: number;
151
+ _score?: number;
152
+ }
153
+ /**
154
+ * Type guard for LanceDB raw search result
155
+ */
156
+ export declare function isLanceDBRawResult(value: unknown): value is LanceDBRawResult;
157
+ /**
158
+ * Convert LanceDB raw result to SearchResult with type validation
159
+ * @throws DatabaseError if the result is invalid
160
+ */
161
+ export declare function toSearchResult(raw: unknown): SearchResult;
162
+ /**
163
+ * Map a raw LanceDB row to a full {@link VectorChunk}, including the stored
164
+ * embedding vector and metadata. Used for backup/restore (ingest rollback),
165
+ * where the row must round-trip back through `insertChunks` intact — unlike
166
+ * {@link toChunkRow} / {@link toSearchResult}, which drop the vector. The
167
+ * embedding is normalized to `number[]` (LanceDB returns a typed array).
168
+ */
169
+ export declare function toVectorChunk(raw: unknown): VectorChunk;
170
+ /** Normalize only the defined legacy no-image sentinels; keep malformed JSON observable. */
171
+ export declare function normalizeVisualAttachments(value: unknown): string;
172
+ /** Parse one persisted attachment cell while keeping malformed siblings observable. */
173
+ export declare function parseHydratedVisualAttachments(value: unknown): {
174
+ attachments: VisualAttachment[];
175
+ omittedCount: number;
176
+ };
177
+ /**
178
+ * Convert LanceDB raw row to ChunkRow with type validation.
179
+ * Mirrors toSearchResult but returns the minimal range-read shape: no score
180
+ * (not ranked) and no metadata (not needed for index-adjacent retrieval).
181
+ *
182
+ * Uses a narrower shape check than isLanceDBRawResult: only
183
+ * filePath/chunkIndex/text are required because getChunksByRange
184
+ * does not project metadata. The empty-string-or-missing fileTitle
185
+ * is normalized to null per §Field Propagation Map.
186
+ *
187
+ * @throws DatabaseError if the raw row is missing required fields
188
+ */
189
+ export declare function toChunkRow(raw: unknown): ChunkRow;
190
+ /**
191
+ * Database error
192
+ */
193
+ export declare class DatabaseError extends AppError {
194
+ constructor(message: string, cause?: Error);
195
+ }
196
+ //# 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,224 @@
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
+ // ============================================
5
+ // Constants
6
+ // ============================================
7
+ /** Multiplier for candidate count in hybrid search (to allow reranking) */
8
+ export const HYBRID_SEARCH_CANDIDATE_MULTIPLIER = 2;
9
+ /** FTS index name (bump version when changing tokenizer settings) */
10
+ export const FTS_INDEX_NAME = 'fts_index_v2';
11
+ /** Threshold for cleaning up old index versions (1 minute) */
12
+ export const FTS_CLEANUP_THRESHOLD_MS = 60 * 1000;
13
+ /** Default hybrid-search weight (vector vs FTS blend) when not configured */
14
+ export const DEFAULT_HYBRID_WEIGHT = 0.6;
15
+ // ============================================
16
+ // Type Guards
17
+ // ============================================
18
+ /**
19
+ * Type guard for DocumentMetadata
20
+ */
21
+ function isDocumentMetadata(value) {
22
+ if (typeof value !== 'object' || value === null)
23
+ return false;
24
+ const obj = value;
25
+ return (typeof obj['fileName'] === 'string' &&
26
+ typeof obj['fileSize'] === 'number' &&
27
+ typeof obj['fileType'] === 'string');
28
+ }
29
+ /**
30
+ * Type guard for LanceDB raw search result
31
+ */
32
+ export function isLanceDBRawResult(value) {
33
+ if (typeof value !== 'object' || value === null)
34
+ return false;
35
+ const obj = value;
36
+ return (typeof obj['id'] === 'string' &&
37
+ typeof obj['filePath'] === 'string' &&
38
+ typeof obj['chunkIndex'] === 'number' &&
39
+ typeof obj['text'] === 'string' &&
40
+ isDocumentMetadata(obj['metadata']));
41
+ }
42
+ /**
43
+ * Convert LanceDB raw result to SearchResult with type validation
44
+ * @throws DatabaseError if the result is invalid
45
+ */
46
+ export function toSearchResult(raw) {
47
+ if (!isLanceDBRawResult(raw)) {
48
+ throw new DatabaseError('Invalid search result format from LanceDB');
49
+ }
50
+ // Score source: vector search rows carry `_distance` (dot distance, the
51
+ // normal path). `_score` is a defensive fallback for any FTS-shaped row that
52
+ // reaches here (the live FTS path consumes `_score` directly in
53
+ // applyKeywordBoost, not via this mapper). The final `?? 0` is an
54
+ // effectively-unreachable guard: vectorSearch always returns `_distance`. It
55
+ // is kept defensive rather than throwing, since a missing score is not worth
56
+ // failing a whole search over.
57
+ return {
58
+ id: raw.id,
59
+ filePath: raw.filePath,
60
+ chunkIndex: raw.chunkIndex,
61
+ text: raw.text,
62
+ score: raw._distance ?? raw._score ?? 0,
63
+ metadata: raw.metadata,
64
+ fileTitle: raw.fileTitle || null,
65
+ };
66
+ }
67
+ /**
68
+ * Map a raw LanceDB row to a full {@link VectorChunk}, including the stored
69
+ * embedding vector and metadata. Used for backup/restore (ingest rollback),
70
+ * where the row must round-trip back through `insertChunks` intact — unlike
71
+ * {@link toChunkRow} / {@link toSearchResult}, which drop the vector. The
72
+ * embedding is normalized to `number[]` (LanceDB returns a typed array).
73
+ */
74
+ export function toVectorChunk(raw) {
75
+ if (typeof raw !== 'object' || raw === null) {
76
+ throw new DatabaseError('Invalid chunk row shape from LanceDB');
77
+ }
78
+ const obj = raw;
79
+ const { id, filePath, chunkIndex, text, vector, metadata, fileTitle, contentHash, visualAttachments, timestamp, } = obj;
80
+ if (typeof id !== 'string' ||
81
+ typeof filePath !== 'string' ||
82
+ typeof chunkIndex !== 'number' ||
83
+ typeof text !== 'string' ||
84
+ typeof timestamp !== 'string') {
85
+ throw new DatabaseError('Invalid chunk row shape from LanceDB (scalar fields)');
86
+ }
87
+ if (!isDocumentMetadata(metadata)) {
88
+ throw new DatabaseError('Invalid chunk row shape from LanceDB (metadata)');
89
+ }
90
+ if (vector == null || typeof vector.length !== 'number') {
91
+ throw new DatabaseError('Invalid chunk row shape from LanceDB (vector)');
92
+ }
93
+ return {
94
+ id,
95
+ filePath,
96
+ chunkIndex,
97
+ text,
98
+ vector: Array.from(vector),
99
+ metadata,
100
+ fileTitle: typeof fileTitle === 'string' && fileTitle.length > 0 ? fileTitle : null,
101
+ // Omit the key rather than store '' or undefined: the create path seeds ''
102
+ // for schema inference, and a '' that survived to a caller would read as a
103
+ // real hash equal to nothing on disk.
104
+ ...(typeof contentHash === 'string' && contentHash.length > 0 ? { contentHash } : {}),
105
+ visualAttachments: normalizeVisualAttachments(visualAttachments),
106
+ timestamp,
107
+ };
108
+ }
109
+ /** Normalize only the defined legacy no-image sentinels; keep malformed JSON observable. */
110
+ export function normalizeVisualAttachments(value) {
111
+ return typeof value === 'string' && value.length > 0 ? value : '[]';
112
+ }
113
+ const VISUAL_RENDITION_MAX_BASE64_LENGTH = Math.ceil(MAX_VISUAL_RENDITION_BYTES / 3) * 4;
114
+ function decodeStrictBase64(value) {
115
+ if (typeof value !== 'string' ||
116
+ value.length === 0 ||
117
+ value.length > VISUAL_RENDITION_MAX_BASE64_LENGTH ||
118
+ value.length % 4 !== 0 ||
119
+ !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(value)) {
120
+ return null;
121
+ }
122
+ const decoded = Buffer.from(value, 'base64');
123
+ return decoded.toString('base64') === value ? decoded : null;
124
+ }
125
+ function isVisualAttachment(value) {
126
+ if (typeof value !== 'object' || value === null)
127
+ return false;
128
+ const attachment = value;
129
+ if (!Number.isInteger(attachment.imageIndex) ||
130
+ attachment.imageIndex < 0 ||
131
+ (attachment.mimeType !== 'image/png' && attachment.mimeType !== 'image/jpeg')) {
132
+ return false;
133
+ }
134
+ const bytes = decodeStrictBase64(attachment.data);
135
+ if (!bytes || bytes.byteLength > MAX_VISUAL_RENDITION_BYTES)
136
+ return false;
137
+ return attachment.mimeType === 'image/png'
138
+ ? bytes.length >= 8 &&
139
+ bytes[0] === 0x89 &&
140
+ bytes[1] === 0x50 &&
141
+ bytes[2] === 0x4e &&
142
+ bytes[3] === 0x47 &&
143
+ bytes[4] === 0x0d &&
144
+ bytes[5] === 0x0a &&
145
+ bytes[6] === 0x1a &&
146
+ bytes[7] === 0x0a
147
+ : bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff;
148
+ }
149
+ /** Parse one persisted attachment cell while keeping malformed siblings observable. */
150
+ export function parseHydratedVisualAttachments(value) {
151
+ if (value === null || value === undefined || value === '' || value === '[]') {
152
+ return { attachments: [], omittedCount: 0 };
153
+ }
154
+ if (typeof value !== 'string')
155
+ return { attachments: [], omittedCount: 1 };
156
+ let parsed;
157
+ try {
158
+ parsed = JSON.parse(value);
159
+ }
160
+ catch {
161
+ return { attachments: [], omittedCount: 1 };
162
+ }
163
+ if (!Array.isArray(parsed))
164
+ return { attachments: [], omittedCount: 1 };
165
+ const attachments = [];
166
+ let omittedCount = 0;
167
+ for (const item of parsed) {
168
+ if (!isVisualAttachment(item)) {
169
+ omittedCount += 1;
170
+ continue;
171
+ }
172
+ attachments.push({
173
+ imageIndex: item.imageIndex,
174
+ mimeType: item.mimeType,
175
+ data: item.data,
176
+ });
177
+ }
178
+ attachments.sort((left, right) => left.imageIndex - right.imageIndex);
179
+ return { attachments, omittedCount };
180
+ }
181
+ /**
182
+ * Convert LanceDB raw row to ChunkRow with type validation.
183
+ * Mirrors toSearchResult but returns the minimal range-read shape: no score
184
+ * (not ranked) and no metadata (not needed for index-adjacent retrieval).
185
+ *
186
+ * Uses a narrower shape check than isLanceDBRawResult: only
187
+ * filePath/chunkIndex/text are required because getChunksByRange
188
+ * does not project metadata. The empty-string-or-missing fileTitle
189
+ * is normalized to null per §Field Propagation Map.
190
+ *
191
+ * @throws DatabaseError if the raw row is missing required fields
192
+ */
193
+ export function toChunkRow(raw) {
194
+ if (typeof raw !== 'object' || raw === null) {
195
+ throw new DatabaseError('Invalid chunk row shape from LanceDB');
196
+ }
197
+ const obj = raw;
198
+ if (typeof obj['filePath'] !== 'string' ||
199
+ typeof obj['chunkIndex'] !== 'number' ||
200
+ typeof obj['text'] !== 'string') {
201
+ throw new DatabaseError('Invalid chunk row shape from LanceDB');
202
+ }
203
+ const rawFileTitle = obj['fileTitle'];
204
+ const fileTitle = typeof rawFileTitle === 'string' && rawFileTitle.length > 0 ? rawFileTitle : null;
205
+ return {
206
+ filePath: obj['filePath'],
207
+ chunkIndex: obj['chunkIndex'],
208
+ text: obj['text'],
209
+ fileTitle,
210
+ };
211
+ }
212
+ // ============================================
213
+ // Error Classes
214
+ // ============================================
215
+ /**
216
+ * Database error
217
+ */
218
+ export class DatabaseError extends AppError {
219
+ constructor(message, cause) {
220
+ super(message, 'vectordb', 'internal', cause);
221
+ this.name = 'DatabaseError';
222
+ }
223
+ }
224
+ //# 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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"}