rag-lite-ts 1.0.2 → 2.0.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 (202) hide show
  1. package/README.md +606 -93
  2. package/dist/cli/indexer.js +192 -4
  3. package/dist/cli/search.js +50 -11
  4. package/dist/cli.js +183 -26
  5. package/dist/core/abstract-embedder.d.ts +125 -0
  6. package/dist/core/abstract-embedder.js +264 -0
  7. package/dist/core/actionable-error-messages.d.ts +60 -0
  8. package/dist/core/actionable-error-messages.js +397 -0
  9. package/dist/core/batch-processing-optimizer.d.ts +155 -0
  10. package/dist/core/batch-processing-optimizer.js +541 -0
  11. package/dist/core/chunker.d.ts +2 -0
  12. package/dist/core/cli-database-utils.d.ts +53 -0
  13. package/dist/core/cli-database-utils.js +239 -0
  14. package/dist/core/config.js +10 -3
  15. package/dist/core/content-errors.d.ts +111 -0
  16. package/dist/core/content-errors.js +362 -0
  17. package/dist/core/content-manager.d.ts +343 -0
  18. package/dist/core/content-manager.js +1504 -0
  19. package/dist/core/content-performance-optimizer.d.ts +150 -0
  20. package/dist/core/content-performance-optimizer.js +516 -0
  21. package/dist/core/content-resolver.d.ts +104 -0
  22. package/dist/core/content-resolver.js +285 -0
  23. package/dist/core/cross-modal-search.d.ts +164 -0
  24. package/dist/core/cross-modal-search.js +342 -0
  25. package/dist/core/database-connection-manager.d.ts +109 -0
  26. package/dist/core/database-connection-manager.js +304 -0
  27. package/dist/core/db.d.ts +141 -2
  28. package/dist/core/db.js +631 -89
  29. package/dist/core/embedder-factory.d.ts +176 -0
  30. package/dist/core/embedder-factory.js +338 -0
  31. package/dist/core/index.d.ts +3 -1
  32. package/dist/core/index.js +4 -1
  33. package/dist/core/ingestion.d.ts +85 -15
  34. package/dist/core/ingestion.js +510 -45
  35. package/dist/core/lazy-dependency-loader.d.ts +152 -0
  36. package/dist/core/lazy-dependency-loader.js +453 -0
  37. package/dist/core/mode-detection-service.d.ts +150 -0
  38. package/dist/core/mode-detection-service.js +565 -0
  39. package/dist/core/mode-model-validator.d.ts +92 -0
  40. package/dist/core/mode-model-validator.js +203 -0
  41. package/dist/core/model-registry.d.ts +120 -0
  42. package/dist/core/model-registry.js +415 -0
  43. package/dist/core/model-validator.d.ts +217 -0
  44. package/dist/core/model-validator.js +782 -0
  45. package/dist/core/polymorphic-search-factory.d.ts +154 -0
  46. package/dist/core/polymorphic-search-factory.js +344 -0
  47. package/dist/core/raglite-paths.d.ts +121 -0
  48. package/dist/core/raglite-paths.js +145 -0
  49. package/dist/core/reranking-config.d.ts +42 -0
  50. package/dist/core/reranking-config.js +156 -0
  51. package/dist/core/reranking-factory.d.ts +92 -0
  52. package/dist/core/reranking-factory.js +591 -0
  53. package/dist/core/reranking-strategies.d.ts +325 -0
  54. package/dist/core/reranking-strategies.js +720 -0
  55. package/dist/core/resource-cleanup.d.ts +163 -0
  56. package/dist/core/resource-cleanup.js +371 -0
  57. package/dist/core/resource-manager.d.ts +212 -0
  58. package/dist/core/resource-manager.js +564 -0
  59. package/dist/core/search.d.ts +28 -1
  60. package/dist/core/search.js +83 -5
  61. package/dist/core/streaming-operations.d.ts +145 -0
  62. package/dist/core/streaming-operations.js +409 -0
  63. package/dist/core/types.d.ts +3 -0
  64. package/dist/core/universal-embedder.d.ts +177 -0
  65. package/dist/core/universal-embedder.js +139 -0
  66. package/dist/core/validation-messages.d.ts +99 -0
  67. package/dist/core/validation-messages.js +334 -0
  68. package/dist/core/vector-index.js +7 -8
  69. package/dist/factories/index.d.ts +1 -1
  70. package/dist/factories/text-factory.d.ts +128 -34
  71. package/dist/factories/text-factory.js +346 -97
  72. package/dist/file-processor.d.ts +88 -2
  73. package/dist/file-processor.js +720 -17
  74. package/dist/index.d.ts +9 -0
  75. package/dist/index.js +11 -0
  76. package/dist/ingestion.d.ts +16 -0
  77. package/dist/ingestion.js +21 -0
  78. package/dist/mcp-server.d.ts +35 -3
  79. package/dist/mcp-server.js +1107 -31
  80. package/dist/multimodal/clip-embedder.d.ts +314 -0
  81. package/dist/multimodal/clip-embedder.js +945 -0
  82. package/dist/multimodal/index.d.ts +6 -0
  83. package/dist/multimodal/index.js +6 -0
  84. package/dist/run-error-recovery-tests.d.ts +7 -0
  85. package/dist/run-error-recovery-tests.js +101 -0
  86. package/dist/search.d.ts +26 -0
  87. package/dist/search.js +54 -1
  88. package/dist/test-utils.d.ts +8 -26
  89. package/dist/text/chunker.d.ts +1 -0
  90. package/dist/text/embedder.js +15 -8
  91. package/dist/text/index.d.ts +1 -0
  92. package/dist/text/index.js +1 -0
  93. package/dist/text/reranker.d.ts +1 -2
  94. package/dist/text/reranker.js +17 -47
  95. package/dist/text/sentence-transformer-embedder.d.ts +96 -0
  96. package/dist/text/sentence-transformer-embedder.js +340 -0
  97. package/dist/types.d.ts +39 -0
  98. package/dist/utils/vector-math.d.ts +31 -0
  99. package/dist/utils/vector-math.js +70 -0
  100. package/package.json +15 -3
  101. package/dist/api-errors.d.ts.map +0 -1
  102. package/dist/api-errors.js.map +0 -1
  103. package/dist/cli/indexer.d.ts.map +0 -1
  104. package/dist/cli/indexer.js.map +0 -1
  105. package/dist/cli/search.d.ts.map +0 -1
  106. package/dist/cli/search.js.map +0 -1
  107. package/dist/cli.d.ts.map +0 -1
  108. package/dist/cli.js.map +0 -1
  109. package/dist/config.d.ts.map +0 -1
  110. package/dist/config.js.map +0 -1
  111. package/dist/core/adapters.d.ts.map +0 -1
  112. package/dist/core/adapters.js.map +0 -1
  113. package/dist/core/chunker.d.ts.map +0 -1
  114. package/dist/core/chunker.js.map +0 -1
  115. package/dist/core/config.d.ts.map +0 -1
  116. package/dist/core/config.js.map +0 -1
  117. package/dist/core/db.d.ts.map +0 -1
  118. package/dist/core/db.js.map +0 -1
  119. package/dist/core/error-handler.d.ts.map +0 -1
  120. package/dist/core/error-handler.js.map +0 -1
  121. package/dist/core/index.d.ts.map +0 -1
  122. package/dist/core/index.js.map +0 -1
  123. package/dist/core/ingestion.d.ts.map +0 -1
  124. package/dist/core/ingestion.js.map +0 -1
  125. package/dist/core/interfaces.d.ts.map +0 -1
  126. package/dist/core/interfaces.js.map +0 -1
  127. package/dist/core/path-manager.d.ts.map +0 -1
  128. package/dist/core/path-manager.js.map +0 -1
  129. package/dist/core/search-example.d.ts +0 -25
  130. package/dist/core/search-example.d.ts.map +0 -1
  131. package/dist/core/search-example.js +0 -138
  132. package/dist/core/search-example.js.map +0 -1
  133. package/dist/core/search-pipeline-example.d.ts +0 -21
  134. package/dist/core/search-pipeline-example.d.ts.map +0 -1
  135. package/dist/core/search-pipeline-example.js +0 -188
  136. package/dist/core/search-pipeline-example.js.map +0 -1
  137. package/dist/core/search-pipeline.d.ts.map +0 -1
  138. package/dist/core/search-pipeline.js.map +0 -1
  139. package/dist/core/search.d.ts.map +0 -1
  140. package/dist/core/search.js.map +0 -1
  141. package/dist/core/types.d.ts.map +0 -1
  142. package/dist/core/types.js.map +0 -1
  143. package/dist/core/vector-index.d.ts.map +0 -1
  144. package/dist/core/vector-index.js.map +0 -1
  145. package/dist/dom-polyfills.d.ts.map +0 -1
  146. package/dist/dom-polyfills.js.map +0 -1
  147. package/dist/examples/clean-api-examples.d.ts +0 -44
  148. package/dist/examples/clean-api-examples.d.ts.map +0 -1
  149. package/dist/examples/clean-api-examples.js +0 -206
  150. package/dist/examples/clean-api-examples.js.map +0 -1
  151. package/dist/factories/index.d.ts.map +0 -1
  152. package/dist/factories/index.js.map +0 -1
  153. package/dist/factories/text-factory.d.ts.map +0 -1
  154. package/dist/factories/text-factory.js.map +0 -1
  155. package/dist/file-processor.d.ts.map +0 -1
  156. package/dist/file-processor.js.map +0 -1
  157. package/dist/index-manager.d.ts.map +0 -1
  158. package/dist/index-manager.js.map +0 -1
  159. package/dist/index.d.ts.map +0 -1
  160. package/dist/index.js.map +0 -1
  161. package/dist/indexer.d.ts.map +0 -1
  162. package/dist/indexer.js.map +0 -1
  163. package/dist/ingestion.d.ts.map +0 -1
  164. package/dist/ingestion.js.map +0 -1
  165. package/dist/mcp-server.d.ts.map +0 -1
  166. package/dist/mcp-server.js.map +0 -1
  167. package/dist/preprocess.d.ts.map +0 -1
  168. package/dist/preprocess.js.map +0 -1
  169. package/dist/preprocessors/index.d.ts.map +0 -1
  170. package/dist/preprocessors/index.js.map +0 -1
  171. package/dist/preprocessors/mdx.d.ts.map +0 -1
  172. package/dist/preprocessors/mdx.js.map +0 -1
  173. package/dist/preprocessors/mermaid.d.ts.map +0 -1
  174. package/dist/preprocessors/mermaid.js.map +0 -1
  175. package/dist/preprocessors/registry.d.ts.map +0 -1
  176. package/dist/preprocessors/registry.js.map +0 -1
  177. package/dist/search-standalone.d.ts.map +0 -1
  178. package/dist/search-standalone.js.map +0 -1
  179. package/dist/search.d.ts.map +0 -1
  180. package/dist/search.js.map +0 -1
  181. package/dist/test-utils.d.ts.map +0 -1
  182. package/dist/test-utils.js.map +0 -1
  183. package/dist/text/chunker.d.ts.map +0 -1
  184. package/dist/text/chunker.js.map +0 -1
  185. package/dist/text/embedder.d.ts.map +0 -1
  186. package/dist/text/embedder.js.map +0 -1
  187. package/dist/text/index.d.ts.map +0 -1
  188. package/dist/text/index.js.map +0 -1
  189. package/dist/text/preprocessors/index.d.ts.map +0 -1
  190. package/dist/text/preprocessors/index.js.map +0 -1
  191. package/dist/text/preprocessors/mdx.d.ts.map +0 -1
  192. package/dist/text/preprocessors/mdx.js.map +0 -1
  193. package/dist/text/preprocessors/mermaid.d.ts.map +0 -1
  194. package/dist/text/preprocessors/mermaid.js.map +0 -1
  195. package/dist/text/preprocessors/registry.d.ts.map +0 -1
  196. package/dist/text/preprocessors/registry.js.map +0 -1
  197. package/dist/text/reranker.d.ts.map +0 -1
  198. package/dist/text/reranker.js.map +0 -1
  199. package/dist/text/tokenizer.d.ts.map +0 -1
  200. package/dist/text/tokenizer.js.map +0 -1
  201. package/dist/types.d.ts.map +0 -1
  202. package/dist/types.js.map +0 -1
@@ -0,0 +1,565 @@
1
+ /**
2
+ * CORE MODULE — Mode Detection Service for Chameleon Architecture
3
+ * Handles automatic mode detection from database and provides default configurations
4
+ * Supports graceful error handling and fallback to text mode
5
+ * Enhanced with shared database connection management to prevent locking issues
6
+ */
7
+ import { getSystemInfo, setSystemInfo, initializeSchema } from './db.js';
8
+ import { DatabaseConnectionManager } from './database-connection-manager.js';
9
+ import { handleError, ErrorCategory, ErrorSeverity, createError } from './error-handler.js';
10
+ // =============================================================================
11
+ // MODE DETECTION SERVICE
12
+ // =============================================================================
13
+ /**
14
+ * Service for detecting and storing system mode configuration
15
+ * Provides automatic mode detection from database with graceful error handling
16
+ * Uses shared database connections to prevent locking issues
17
+ */
18
+ export class ModeDetectionService {
19
+ dbPath;
20
+ constructor(dbPath) {
21
+ this.dbPath = dbPath;
22
+ }
23
+ /**
24
+ * Detects the current system mode from the database
25
+ * Falls back to default text mode configuration for new installations
26
+ * Enhanced with comprehensive error handling and recovery mechanisms
27
+ * Uses shared database connections to prevent locking issues
28
+ *
29
+ * @param existingConnection - Optional existing connection to reuse
30
+ * @returns Promise resolving to SystemInfo with current or default configuration
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const modeService = new ModeDetectionService('./db.sqlite');
35
+ * const systemInfo = await modeService.detectMode();
36
+ * console.log(`Current mode: ${systemInfo.mode}`);
37
+ * ```
38
+ */
39
+ async detectMode(existingConnection) {
40
+ let connection = null;
41
+ let shouldReleaseConnection = false;
42
+ try {
43
+ console.log(`🔍 Detecting system mode from database: ${this.dbPath}`);
44
+ // Pre-flight check: Verify database accessibility
45
+ const accessibility = await this.checkDatabaseAccessibility();
46
+ console.log(`📊 Database accessibility check:`);
47
+ console.log(` Exists: ${accessibility.exists}`);
48
+ console.log(` Readable: ${accessibility.readable}`);
49
+ console.log(` Writable: ${accessibility.writable}`);
50
+ console.log(` Size: ${accessibility.size} bytes`);
51
+ if (accessibility.error) {
52
+ console.log(` Error: ${accessibility.error}`);
53
+ }
54
+ // Handle accessibility issues proactively
55
+ if (!accessibility.exists) {
56
+ console.log('📁 Database file does not exist - this is a new installation');
57
+ return this.getDefaultSystemInfo();
58
+ }
59
+ if (!accessibility.readable) {
60
+ throw new Error(`Database file is not readable. Check file permissions for ${this.dbPath}`);
61
+ }
62
+ if (accessibility.size === 0) {
63
+ console.log('📄 Database file is empty - treating as new installation');
64
+ return this.getDefaultSystemInfo();
65
+ }
66
+ // Use existing connection or get managed connection
67
+ if (existingConnection) {
68
+ connection = existingConnection;
69
+ console.log('🔄 Using existing database connection');
70
+ }
71
+ else {
72
+ try {
73
+ connection = await DatabaseConnectionManager.getConnection(this.dbPath);
74
+ shouldReleaseConnection = true;
75
+ console.log('✅ Database connection established successfully');
76
+ }
77
+ catch (dbError) {
78
+ console.log('⚠️ Database connection failed, analyzing error...');
79
+ throw dbError; // Re-throw to be handled by main catch block
80
+ }
81
+ }
82
+ // Verify database schema integrity
83
+ console.log('🔍 Checking database schema integrity...');
84
+ try {
85
+ await this.verifySchemaIntegrity(connection);
86
+ console.log('✅ Database schema exists and is accessible');
87
+ }
88
+ catch (schemaError) {
89
+ console.log('⚠️ Database schema verification failed');
90
+ throw schemaError;
91
+ }
92
+ console.log('✅ Database schema verified');
93
+ // Attempt to retrieve system info
94
+ console.log('📖 Retrieving system configuration from database...');
95
+ let systemInfo = null;
96
+ try {
97
+ systemInfo = await getSystemInfo(connection);
98
+ console.log('✅ System info retrieved from database');
99
+ }
100
+ catch (retrievalError) {
101
+ console.log('⚠️ System info retrieval failed');
102
+ throw retrievalError;
103
+ }
104
+ // Handle missing system info (new installation)
105
+ if (!systemInfo) {
106
+ console.log('📝 No system configuration found - this appears to be a new installation');
107
+ return this.getDefaultSystemInfo();
108
+ }
109
+ // Validate retrieved system info
110
+ console.log('🔍 Validating system configuration...');
111
+ try {
112
+ this.validateSystemInfo(systemInfo);
113
+ console.log('✅ System configuration validation passed');
114
+ }
115
+ catch (validationError) {
116
+ console.log('⚠️ System configuration validation failed');
117
+ throw validationError;
118
+ }
119
+ console.log('✅ System configuration validated successfully');
120
+ // Success - log detailed configuration info
121
+ console.log(`🎯 Mode detection successful!`);
122
+ console.log(` Mode: ${systemInfo.mode}`);
123
+ console.log(` Model: ${systemInfo.modelName} (${systemInfo.modelType})`);
124
+ console.log(` Dimensions: ${systemInfo.modelDimensions}`);
125
+ console.log(` Content Types: ${systemInfo.supportedContentTypes.join(', ')}`);
126
+ console.log(` Reranking: ${systemInfo.rerankingStrategy}`);
127
+ return systemInfo;
128
+ }
129
+ catch (error) {
130
+ console.log('❌ Mode detection encountered an error, initiating fallback procedure...');
131
+ return this.handleDetectionError(error);
132
+ }
133
+ finally {
134
+ // Enhanced connection cleanup with managed connections
135
+ if (shouldReleaseConnection && connection) {
136
+ try {
137
+ await DatabaseConnectionManager.releaseConnection(this.dbPath);
138
+ console.log('✅ Database connection released successfully');
139
+ }
140
+ catch (closeError) {
141
+ console.warn('⚠️ Warning: Failed to release database connection cleanly:', closeError instanceof Error ? closeError.message : closeError);
142
+ // Log additional context for debugging
143
+ if (closeError instanceof Error && closeError.message.includes('SQLITE_BUSY')) {
144
+ console.warn('💡 Database may still be processing operations. This is usually harmless.');
145
+ }
146
+ }
147
+ }
148
+ }
149
+ }
150
+ /**
151
+ * Stores system mode configuration in the database
152
+ * Creates or updates the system_info table with the provided configuration
153
+ * Uses shared database connections to prevent locking issues
154
+ *
155
+ * @param systemInfo - SystemInfo object to store (can be partial for updates)
156
+ * @param existingConnection - Optional existing connection to reuse
157
+ *
158
+ * @example
159
+ * ```typescript
160
+ * const modeService = new ModeDetectionService('./db.sqlite');
161
+ * await modeService.storeMode({
162
+ * mode: 'multimodal',
163
+ * modelName: 'Xenova/clip-vit-base-patch32',
164
+ * modelType: 'clip',
165
+ * modelDimensions: 512,
166
+ * supportedContentTypes: ['text', 'image'],
167
+ * rerankingStrategy: 'text-derived'
168
+ * });
169
+ * ```
170
+ */
171
+ async storeMode(systemInfo, existingConnection) {
172
+ let connection = null;
173
+ let shouldReleaseConnection = false;
174
+ try {
175
+ // Validate the system info before storing
176
+ if (systemInfo.mode) {
177
+ this.validateMode(systemInfo.mode);
178
+ }
179
+ if (systemInfo.modelType) {
180
+ this.validateModelType(systemInfo.modelType);
181
+ }
182
+ if (systemInfo.rerankingStrategy) {
183
+ this.validateRerankingStrategy(systemInfo.rerankingStrategy);
184
+ }
185
+ // Use existing connection or get managed connection
186
+ if (existingConnection) {
187
+ connection = existingConnection;
188
+ }
189
+ else {
190
+ connection = await DatabaseConnectionManager.getConnection(this.dbPath);
191
+ shouldReleaseConnection = true;
192
+ }
193
+ // Initialize schema if it doesn't exist
194
+ await this.ensureSchemaExists(connection);
195
+ await setSystemInfo(connection, systemInfo);
196
+ console.log(`✅ Mode configuration stored successfully: ${systemInfo.mode || 'partial update'}`);
197
+ }
198
+ catch (error) {
199
+ const enhancedError = this.enhanceStorageError(error, systemInfo);
200
+ handleError(enhancedError, 'Mode Storage', {
201
+ severity: ErrorSeverity.ERROR,
202
+ category: ErrorCategory.DATABASE
203
+ });
204
+ throw enhancedError;
205
+ }
206
+ finally {
207
+ if (shouldReleaseConnection && connection) {
208
+ try {
209
+ await DatabaseConnectionManager.releaseConnection(this.dbPath);
210
+ }
211
+ catch (closeError) {
212
+ console.warn('Warning: Failed to release database connection:', closeError);
213
+ }
214
+ }
215
+ }
216
+ }
217
+ /**
218
+ * Gets the current mode from the database (convenience method)
219
+ * @returns Promise resolving to the current mode string
220
+ */
221
+ async getCurrentMode() {
222
+ const systemInfo = await this.detectMode();
223
+ return systemInfo.mode;
224
+ }
225
+ /**
226
+ * Checks if the system is in multimodal mode
227
+ * @returns Promise resolving to boolean indicating multimodal mode
228
+ */
229
+ async isMultimodalMode() {
230
+ const mode = await this.getCurrentMode();
231
+ return mode === 'multimodal';
232
+ }
233
+ /**
234
+ * Gets complete model information from the database
235
+ * @returns Promise resolving to current model configuration
236
+ */
237
+ async getCurrentModelInfo() {
238
+ const systemInfo = await this.detectMode();
239
+ return {
240
+ modelName: systemInfo.modelName,
241
+ modelType: systemInfo.modelType,
242
+ dimensions: systemInfo.modelDimensions,
243
+ supportedContentTypes: systemInfo.supportedContentTypes
244
+ };
245
+ }
246
+ // =============================================================================
247
+ // PRIVATE HELPER METHODS
248
+ // =============================================================================
249
+ /**
250
+ * Get default system info for new installations
251
+ * @private
252
+ */
253
+ getDefaultSystemInfo() {
254
+ return {
255
+ mode: 'text',
256
+ modelName: 'sentence-transformers/all-MiniLM-L6-v2',
257
+ modelType: 'sentence-transformer',
258
+ modelDimensions: 384,
259
+ modelVersion: '1.0.0',
260
+ supportedContentTypes: ['text'],
261
+ rerankingStrategy: 'cross-encoder',
262
+ rerankingModel: 'Xenova/ms-marco-MiniLM-L-6-v2',
263
+ rerankingConfig: undefined,
264
+ createdAt: new Date(),
265
+ updatedAt: new Date()
266
+ };
267
+ }
268
+ /**
269
+ * Check database file accessibility
270
+ * @private
271
+ */
272
+ async checkDatabaseAccessibility() {
273
+ try {
274
+ const fs = await import('fs');
275
+ const path = this.dbPath;
276
+ const exists = fs.existsSync(path);
277
+ if (!exists) {
278
+ return { exists: false, readable: false, writable: false, size: 0 };
279
+ }
280
+ const stats = fs.statSync(path);
281
+ const size = stats.size;
282
+ // Test readability
283
+ let readable = true;
284
+ try {
285
+ fs.accessSync(path, fs.constants.R_OK);
286
+ }
287
+ catch {
288
+ readable = false;
289
+ }
290
+ // Test writability
291
+ let writable = true;
292
+ try {
293
+ fs.accessSync(path, fs.constants.W_OK);
294
+ }
295
+ catch {
296
+ writable = false;
297
+ }
298
+ return { exists, readable, writable, size };
299
+ }
300
+ catch (error) {
301
+ return {
302
+ exists: false,
303
+ readable: false,
304
+ writable: false,
305
+ size: 0,
306
+ error: error instanceof Error ? error.message : String(error)
307
+ };
308
+ }
309
+ }
310
+ /**
311
+ * Verify database schema integrity
312
+ * @private
313
+ */
314
+ async verifySchemaIntegrity(connection) {
315
+ try {
316
+ // Check if system_info table exists
317
+ const result = await connection.get("SELECT name FROM sqlite_master WHERE type='table' AND name='system_info'");
318
+ if (!result) {
319
+ throw new Error('system_info table does not exist');
320
+ }
321
+ // Verify table structure by attempting a simple query
322
+ await connection.get('SELECT COUNT(*) as count FROM system_info');
323
+ }
324
+ catch (error) {
325
+ throw new Error(`Database schema verification failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
326
+ }
327
+ }
328
+ /**
329
+ * Ensure database schema exists
330
+ * @private
331
+ */
332
+ async ensureSchemaExists(connection) {
333
+ try {
334
+ await initializeSchema(connection);
335
+ }
336
+ catch (error) {
337
+ throw new Error(`Failed to initialize database schema: ${error instanceof Error ? error.message : 'Unknown error'}`);
338
+ }
339
+ }
340
+ /**
341
+ * Handle detection errors with fallback to default configuration
342
+ * @private
343
+ */
344
+ handleDetectionError(error) {
345
+ console.log('🔄 Handling mode detection error with fallback to default configuration...');
346
+ if (error instanceof Error) {
347
+ console.log(` Error details: ${error.message}`);
348
+ // Provide specific guidance based on error type
349
+ this.logErrorGuidance(error);
350
+ }
351
+ else {
352
+ console.log(` Unknown error: ${String(error)}`);
353
+ }
354
+ const defaultInfo = this.getDefaultSystemInfo();
355
+ console.log(`✅ Fallback complete - using default configuration: ${defaultInfo.mode} mode`);
356
+ return defaultInfo;
357
+ }
358
+ /**
359
+ * Log error-specific guidance for users
360
+ * @private
361
+ */
362
+ logErrorGuidance(error) {
363
+ console.log('');
364
+ console.log('🔧 Troubleshooting suggestions:');
365
+ if (error.message.includes('ENOENT') || error.message.includes('no such file')) {
366
+ console.log(' • Database file not found - this is normal for first-time use');
367
+ console.log(' • Run ingestion to create the database');
368
+ console.log(' • Use --mode parameter to set your preferred mode');
369
+ }
370
+ else if (error.message.includes('SQLITE_CORRUPT')) {
371
+ console.log(' • Backup any important data if possible');
372
+ console.log(` • Delete the corrupted database: rm "${this.dbPath}"`);
373
+ console.log(' • Re-run ingestion to recreate the database');
374
+ console.log(' • Consider using database integrity check tools');
375
+ }
376
+ else if (error.message.includes('SQLITE_BUSY') || error.message.includes('locked')) {
377
+ console.log(' • Close any other RAG-lite instances');
378
+ console.log(' • Wait for ongoing operations to complete');
379
+ console.log(' • Check for zombie processes: ps aux | grep raglite');
380
+ console.log(' • Restart your terminal/IDE if needed');
381
+ }
382
+ else if (error.message.includes('permission') || error.message.includes('EACCES')) {
383
+ console.log(` • Check file permissions: ls -la "${this.dbPath}"`);
384
+ console.log(` • Make file writable: chmod 644 "${this.dbPath}"`);
385
+ console.log(' • Ensure directory is writable');
386
+ console.log(' • Run with appropriate user permissions');
387
+ }
388
+ else if (error.message.includes('SQLITE_FULL') || error.message.includes('disk full')) {
389
+ console.log(' • Free up disk space');
390
+ console.log(' • Move database to location with more space');
391
+ console.log(' • Clean up temporary files');
392
+ console.log(' • Check disk usage: df -h');
393
+ }
394
+ else if (error.message.includes('no such table') || error.message.includes('schema')) {
395
+ console.log(' • Re-run ingestion to update database schema');
396
+ console.log(' • Or delete database and start fresh');
397
+ console.log(' • Check if database was created with older version');
398
+ }
399
+ else {
400
+ console.log(' • Check the error message above for specific details');
401
+ console.log(' • Try running ingestion to recreate the database');
402
+ console.log(' • If problem persists, report it as a bug');
403
+ console.log(` • Database path: ${this.dbPath}`);
404
+ }
405
+ console.log('');
406
+ console.log('💡 For immediate use, the system will continue with default text mode.');
407
+ }
408
+ /**
409
+ * Enhances storage errors with more context and helpful suggestions
410
+ * @private
411
+ */
412
+ enhanceStorageError(error, systemInfo) {
413
+ if (error instanceof Error) {
414
+ let enhancedMessage = `Failed to store mode configuration: ${error.message}`;
415
+ if (error.message.includes('UNIQUE constraint failed')) {
416
+ enhancedMessage = 'System info already exists. This should not happen with proper upsert logic.';
417
+ }
418
+ else if (error.message.includes('CHECK constraint failed')) {
419
+ enhancedMessage = `Invalid configuration values provided. Check mode, model_type, and reranking_strategy values.`;
420
+ if (systemInfo.mode && !['text', 'multimodal'].includes(systemInfo.mode)) {
421
+ enhancedMessage += `\nInvalid mode: '${systemInfo.mode}'. Must be 'text' or 'multimodal'.`;
422
+ }
423
+ if (systemInfo.modelType && !['sentence-transformer', 'clip'].includes(systemInfo.modelType)) {
424
+ enhancedMessage += `\nInvalid model type: '${systemInfo.modelType}'. Must be 'sentence-transformer' or 'clip'.`;
425
+ }
426
+ if (systemInfo.rerankingStrategy && !['cross-encoder', 'text-derived', 'metadata', 'hybrid', 'disabled'].includes(systemInfo.rerankingStrategy)) {
427
+ enhancedMessage += `\nInvalid reranking strategy: '${systemInfo.rerankingStrategy}'.`;
428
+ }
429
+ }
430
+ else if (error.message.includes('SQLITE_READONLY')) {
431
+ enhancedMessage = 'Database is read-only. Check file permissions and ensure the database file is writable.';
432
+ }
433
+ return new Error(enhancedMessage);
434
+ }
435
+ return new Error(`Failed to store mode configuration: ${String(error)}`);
436
+ }
437
+ /**
438
+ * Validate complete system info object
439
+ * @private
440
+ */
441
+ validateSystemInfo(systemInfo) {
442
+ console.log('🔍 Validating system configuration...');
443
+ // Check for required fields
444
+ const missingFields = [];
445
+ if (!systemInfo.mode)
446
+ missingFields.push('mode');
447
+ if (!systemInfo.modelName)
448
+ missingFields.push('modelName');
449
+ if (!systemInfo.modelType)
450
+ missingFields.push('modelType');
451
+ if (missingFields.length > 0) {
452
+ throw createError.validation(`Incomplete system configuration in database. Missing fields: ${missingFields.join(', ')}. ` +
453
+ `This may indicate database corruption or an incomplete installation. ` +
454
+ `Consider re-running ingestion to fix the configuration.`);
455
+ }
456
+ // Validate individual fields
457
+ try {
458
+ this.validateMode(systemInfo.mode);
459
+ }
460
+ catch (modeError) {
461
+ throw createError.validation(`Invalid mode '${systemInfo.mode}' found in database. Expected 'text' or 'multimodal'. ` +
462
+ `This may indicate database corruption. Consider re-running ingestion.`);
463
+ }
464
+ try {
465
+ this.validateModelType(systemInfo.modelType);
466
+ }
467
+ catch (typeError) {
468
+ throw createError.validation(`Invalid model type '${systemInfo.modelType}' found in database. Expected 'sentence-transformer' or 'clip'. ` +
469
+ `This may indicate database corruption. Consider re-running ingestion.`);
470
+ }
471
+ if (systemInfo.rerankingStrategy) {
472
+ try {
473
+ this.validateRerankingStrategy(systemInfo.rerankingStrategy);
474
+ }
475
+ catch (strategyError) {
476
+ throw createError.validation(`Invalid reranking strategy '${systemInfo.rerankingStrategy}' found in database. ` +
477
+ `This may indicate database corruption. Consider re-running ingestion.`);
478
+ }
479
+ }
480
+ // Validate supported content types
481
+ if (!Array.isArray(systemInfo.supportedContentTypes)) {
482
+ throw createError.validation(`Invalid supported content types format in database. Expected array, got ${typeof systemInfo.supportedContentTypes}. ` +
483
+ `This may indicate database corruption. Consider re-running ingestion.`);
484
+ }
485
+ if (systemInfo.supportedContentTypes.length === 0) {
486
+ throw createError.validation(`Empty supported content types array in database. At least one content type must be supported. ` +
487
+ `This may indicate database corruption. Consider re-running ingestion.`);
488
+ }
489
+ // Validate model dimensions
490
+ if (typeof systemInfo.modelDimensions !== 'number') {
491
+ throw createError.validation(`Invalid model dimensions type in database. Expected number, got ${typeof systemInfo.modelDimensions}. ` +
492
+ `This may indicate database corruption. Consider re-running ingestion.`);
493
+ }
494
+ if (systemInfo.modelDimensions <= 0) {
495
+ throw createError.validation(`Invalid model dimensions value in database: ${systemInfo.modelDimensions}. Must be positive. ` +
496
+ `This may indicate database corruption. Consider re-running ingestion.`);
497
+ }
498
+ // Warn about unusual dimensions (but don't fail)
499
+ if (systemInfo.modelDimensions < 50 || systemInfo.modelDimensions > 2048) {
500
+ console.warn(`⚠️ Unusual model dimensions detected: ${systemInfo.modelDimensions}. This may indicate configuration issues.`);
501
+ }
502
+ console.log('✅ System configuration validation completed successfully');
503
+ }
504
+ /**
505
+ * Validate mode value
506
+ * @private
507
+ */
508
+ validateMode(mode) {
509
+ const validModes = ['text', 'multimodal'];
510
+ if (!validModes.includes(mode)) {
511
+ throw createError.validation(`Invalid mode '${mode}'. Must be one of: ${validModes.join(', ')}`);
512
+ }
513
+ }
514
+ /**
515
+ * Validate model type value
516
+ * @private
517
+ */
518
+ validateModelType(modelType) {
519
+ const validTypes = ['sentence-transformer', 'clip'];
520
+ if (!validTypes.includes(modelType)) {
521
+ throw createError.validation(`Invalid model type '${modelType}'. Must be one of: ${validTypes.join(', ')}`);
522
+ }
523
+ }
524
+ /**
525
+ * Validate reranking strategy value
526
+ * @private
527
+ */
528
+ validateRerankingStrategy(strategy) {
529
+ const validStrategies = ['cross-encoder', 'text-derived', 'metadata', 'hybrid', 'disabled'];
530
+ if (!validStrategies.includes(strategy)) {
531
+ throw createError.validation(`Invalid reranking strategy '${strategy}'. Must be one of: ${validStrategies.join(', ')}`);
532
+ }
533
+ }
534
+ }
535
+ // =============================================================================
536
+ // CONVENIENCE FUNCTIONS
537
+ // =============================================================================
538
+ /**
539
+ * Quick function to detect mode from database
540
+ * @param dbPath - Path to database file
541
+ * @returns Promise resolving to SystemInfo
542
+ */
543
+ export async function detectSystemMode(dbPath) {
544
+ const service = new ModeDetectionService(dbPath);
545
+ return service.detectMode();
546
+ }
547
+ /**
548
+ * Quick function to store mode configuration
549
+ * @param dbPath - Path to database file
550
+ * @param systemInfo - System configuration to store
551
+ */
552
+ export async function storeSystemMode(dbPath, systemInfo) {
553
+ const service = new ModeDetectionService(dbPath);
554
+ await service.storeMode(systemInfo);
555
+ }
556
+ /**
557
+ * Quick function to check if system is in multimodal mode
558
+ * @param dbPath - Path to database file
559
+ * @returns Promise resolving to boolean
560
+ */
561
+ export async function isMultimodalMode(dbPath) {
562
+ const service = new ModeDetectionService(dbPath);
563
+ return service.isMultimodalMode();
564
+ }
565
+ //# sourceMappingURL=mode-detection-service.js.map
@@ -0,0 +1,92 @@
1
+ /**
2
+ * CORE MODULE — Mode-Model Compatibility Validator
3
+ * Validates compatibility between processing modes and embedding models
4
+ * Provides clear error messages for incompatible configurations
5
+ */
6
+ import type { ModeType } from '../types.js';
7
+ /**
8
+ * Validation result for mode-model compatibility
9
+ */
10
+ export interface ModeModelValidationResult {
11
+ isValid: boolean;
12
+ errors: string[];
13
+ warnings: string[];
14
+ suggestions: string[];
15
+ recommendedModels?: string[];
16
+ }
17
+ /**
18
+ * Validate compatibility between a mode and model
19
+ *
20
+ * @param mode - Processing mode (text or multimodal)
21
+ * @param modelName - Name of the embedding model
22
+ * @returns Validation result with errors and suggestions
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * const result = validateModeModelCompatibility('multimodal', 'sentence-transformers/all-MiniLM-L6-v2');
27
+ * if (!result.isValid) {
28
+ * console.error('Incompatible configuration:', result.errors);
29
+ * console.log('Suggestions:', result.suggestions);
30
+ * }
31
+ * ```
32
+ */
33
+ export declare function validateModeModelCompatibility(mode: ModeType, modelName: string): ModeModelValidationResult;
34
+ /**
35
+ * Validate mode-model compatibility and throw clear error if invalid
36
+ *
37
+ * @param mode - Processing mode
38
+ * @param modelName - Name of the embedding model
39
+ * @throws {Error} If the combination is invalid, with actionable error message
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * try {
44
+ * validateModeModelCompatibilityOrThrow('multimodal', 'sentence-transformers/all-MiniLM-L6-v2');
45
+ * } catch (error) {
46
+ * console.error('Configuration error:', error.message);
47
+ * }
48
+ * ```
49
+ */
50
+ export declare function validateModeModelCompatibilityOrThrow(mode: ModeType, modelName: string): void;
51
+ /**
52
+ * Get recommended models for a specific mode
53
+ *
54
+ * @param mode - Processing mode
55
+ * @returns Array of recommended model names
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const textModels = getRecommendedModelsForMode('text');
60
+ * const multimodalModels = getRecommendedModelsForMode('multimodal');
61
+ * ```
62
+ */
63
+ export declare function getRecommendedModelsForMode(mode: ModeType): string[];
64
+ /**
65
+ * Check if a model is compatible with a mode (without detailed validation)
66
+ *
67
+ * @param mode - Processing mode
68
+ * @param modelName - Name of the embedding model
69
+ * @returns True if compatible, false otherwise
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * if (isModeModelCompatible('multimodal', 'Xenova/clip-vit-base-patch32')) {
74
+ * // Proceed with configuration
75
+ * }
76
+ * ```
77
+ */
78
+ export declare function isModeModelCompatible(mode: ModeType, modelName: string): boolean;
79
+ /**
80
+ * Get all compatible models for a specific mode
81
+ *
82
+ * @param mode - Processing mode
83
+ * @returns Array of compatible model names
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const compatibleModels = getCompatibleModelsForMode('multimodal');
88
+ * console.log('Compatible models:', compatibleModels);
89
+ * ```
90
+ */
91
+ export declare function getCompatibleModelsForMode(mode: ModeType): string[];
92
+ //# sourceMappingURL=mode-model-validator.d.ts.map