rag-lite-ts 2.2.0 → 2.3.1

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 (100) hide show
  1. package/README.md +88 -5
  2. package/dist/cjs/cli/indexer.js +73 -15
  3. package/dist/cjs/cli/search.js +77 -2
  4. package/dist/cjs/cli/ui-server.d.ts +5 -0
  5. package/dist/cjs/cli/ui-server.js +152 -0
  6. package/dist/cjs/cli.js +53 -7
  7. package/dist/cjs/core/abstract-generator.d.ts +97 -0
  8. package/dist/cjs/core/abstract-generator.js +222 -0
  9. package/dist/cjs/core/binary-index-format.js +53 -10
  10. package/dist/cjs/core/db.d.ts +56 -0
  11. package/dist/cjs/core/db.js +105 -0
  12. package/dist/cjs/core/generator-registry.d.ts +114 -0
  13. package/dist/cjs/core/generator-registry.js +280 -0
  14. package/dist/cjs/core/index.d.ts +4 -0
  15. package/dist/cjs/core/index.js +11 -0
  16. package/dist/cjs/core/ingestion.js +3 -0
  17. package/dist/cjs/core/knowledge-base-manager.d.ts +109 -0
  18. package/dist/cjs/core/knowledge-base-manager.js +256 -0
  19. package/dist/cjs/core/lazy-dependency-loader.d.ts +43 -0
  20. package/dist/cjs/core/lazy-dependency-loader.js +111 -2
  21. package/dist/cjs/core/prompt-templates.d.ts +138 -0
  22. package/dist/cjs/core/prompt-templates.js +225 -0
  23. package/dist/cjs/core/response-generator.d.ts +132 -0
  24. package/dist/cjs/core/response-generator.js +69 -0
  25. package/dist/cjs/core/search-pipeline.js +1 -1
  26. package/dist/cjs/core/search.d.ts +72 -1
  27. package/dist/cjs/core/search.js +80 -7
  28. package/dist/cjs/core/types.d.ts +1 -0
  29. package/dist/cjs/core/vector-index-messages.d.ts +52 -0
  30. package/dist/cjs/core/vector-index-messages.js +5 -0
  31. package/dist/cjs/core/vector-index-worker.d.ts +6 -0
  32. package/dist/cjs/core/vector-index-worker.js +314 -0
  33. package/dist/cjs/core/vector-index.d.ts +45 -10
  34. package/dist/cjs/core/vector-index.js +279 -218
  35. package/dist/cjs/factories/generator-factory.d.ts +88 -0
  36. package/dist/cjs/factories/generator-factory.js +151 -0
  37. package/dist/cjs/factories/index.d.ts +1 -0
  38. package/dist/cjs/factories/index.js +5 -0
  39. package/dist/cjs/factories/ingestion-factory.js +3 -7
  40. package/dist/cjs/factories/search-factory.js +11 -0
  41. package/dist/cjs/index-manager.d.ts +23 -3
  42. package/dist/cjs/index-manager.js +84 -15
  43. package/dist/cjs/index.d.ts +11 -1
  44. package/dist/cjs/index.js +19 -1
  45. package/dist/cjs/text/generators/causal-lm-generator.d.ts +65 -0
  46. package/dist/cjs/text/generators/causal-lm-generator.js +197 -0
  47. package/dist/cjs/text/generators/index.d.ts +10 -0
  48. package/dist/cjs/text/generators/index.js +10 -0
  49. package/dist/cjs/text/generators/instruct-generator.d.ts +62 -0
  50. package/dist/cjs/text/generators/instruct-generator.js +192 -0
  51. package/dist/esm/cli/indexer.js +73 -15
  52. package/dist/esm/cli/search.js +77 -2
  53. package/dist/esm/cli/ui-server.d.ts +5 -0
  54. package/dist/esm/cli/ui-server.js +152 -0
  55. package/dist/esm/cli.js +53 -7
  56. package/dist/esm/core/abstract-generator.d.ts +97 -0
  57. package/dist/esm/core/abstract-generator.js +222 -0
  58. package/dist/esm/core/binary-index-format.js +53 -10
  59. package/dist/esm/core/db.d.ts +56 -0
  60. package/dist/esm/core/db.js +105 -0
  61. package/dist/esm/core/generator-registry.d.ts +114 -0
  62. package/dist/esm/core/generator-registry.js +280 -0
  63. package/dist/esm/core/index.d.ts +4 -0
  64. package/dist/esm/core/index.js +11 -0
  65. package/dist/esm/core/ingestion.js +3 -0
  66. package/dist/esm/core/knowledge-base-manager.d.ts +109 -0
  67. package/dist/esm/core/knowledge-base-manager.js +256 -0
  68. package/dist/esm/core/lazy-dependency-loader.d.ts +43 -0
  69. package/dist/esm/core/lazy-dependency-loader.js +111 -2
  70. package/dist/esm/core/prompt-templates.d.ts +138 -0
  71. package/dist/esm/core/prompt-templates.js +225 -0
  72. package/dist/esm/core/response-generator.d.ts +132 -0
  73. package/dist/esm/core/response-generator.js +69 -0
  74. package/dist/esm/core/search-pipeline.js +1 -1
  75. package/dist/esm/core/search.d.ts +72 -1
  76. package/dist/esm/core/search.js +80 -7
  77. package/dist/esm/core/types.d.ts +1 -0
  78. package/dist/esm/core/vector-index-messages.d.ts +52 -0
  79. package/dist/esm/core/vector-index-messages.js +5 -0
  80. package/dist/esm/core/vector-index-worker.d.ts +6 -0
  81. package/dist/esm/core/vector-index-worker.js +314 -0
  82. package/dist/esm/core/vector-index.d.ts +45 -10
  83. package/dist/esm/core/vector-index.js +279 -218
  84. package/dist/esm/factories/generator-factory.d.ts +88 -0
  85. package/dist/esm/factories/generator-factory.js +151 -0
  86. package/dist/esm/factories/index.d.ts +1 -0
  87. package/dist/esm/factories/index.js +5 -0
  88. package/dist/esm/factories/ingestion-factory.js +3 -7
  89. package/dist/esm/factories/search-factory.js +11 -0
  90. package/dist/esm/index-manager.d.ts +23 -3
  91. package/dist/esm/index-manager.js +84 -15
  92. package/dist/esm/index.d.ts +11 -1
  93. package/dist/esm/index.js +19 -1
  94. package/dist/esm/text/generators/causal-lm-generator.d.ts +65 -0
  95. package/dist/esm/text/generators/causal-lm-generator.js +197 -0
  96. package/dist/esm/text/generators/index.d.ts +10 -0
  97. package/dist/esm/text/generators/index.js +10 -0
  98. package/dist/esm/text/generators/instruct-generator.d.ts +62 -0
  99. package/dist/esm/text/generators/instruct-generator.js +192 -0
  100. package/package.json +14 -7
@@ -132,7 +132,7 @@ export async function runSearch(query, options = {}) {
132
132
  process.exit(EXIT_CODES.MODEL_ERROR);
133
133
  }
134
134
  }
135
- // Prepare search options
135
+ // Prepare search options (with generation support)
136
136
  const searchOptions = {};
137
137
  if (options['top-k'] !== undefined) {
138
138
  searchOptions.top_k = options['top-k'];
@@ -164,9 +164,60 @@ export async function runSearch(query, options = {}) {
164
164
  }
165
165
  // Track whether reranking will actually be used in this search
166
166
  const rerankingUsed = searchOptions.rerank === true;
167
+ // Handle generation options (experimental, text mode only)
168
+ const generateResponse = options.generate === true;
169
+ const generatorModel = options.generator;
170
+ const maxGenerationTokens = options['max-tokens'];
171
+ const generationTemperature = options.temperature;
172
+ const maxChunksForContext = options['max-chunks'];
173
+ // Generation only supported in text mode
174
+ if (generateResponse && isImage) {
175
+ console.warn('⚠️ [EXPERIMENTAL] Generation is only supported for text searches.');
176
+ console.warn(' Image search results will be returned without generation.');
177
+ console.warn('');
178
+ }
179
+ // Generation requires reranking - enable it automatically
180
+ let rerankingEnabledForGeneration = false;
181
+ if (generateResponse && !isImage && !searchOptions.rerank) {
182
+ searchOptions.rerank = true;
183
+ rerankingEnabledForGeneration = true;
184
+ console.log('📋 Reranking automatically enabled (required for generation)');
185
+ }
186
+ // Set up generator if generation is requested (text mode only)
187
+ let generateFn;
188
+ if (generateResponse && !isImage) {
189
+ try {
190
+ console.log('🤖 [EXPERIMENTAL] Initializing response generator...');
191
+ const { createGenerateFunctionFromModel, getDefaultGeneratorModel } = await import('../factories/generator-factory.js');
192
+ const { getDefaultMaxChunksForContext } = await import('../core/generator-registry.js');
193
+ const modelToUse = generatorModel || getDefaultGeneratorModel();
194
+ const defaultChunks = getDefaultMaxChunksForContext(modelToUse) || 3;
195
+ console.log(` Model: ${modelToUse}`);
196
+ console.log(` Max chunks for context: ${maxChunksForContext || defaultChunks} (default: ${defaultChunks})`);
197
+ generateFn = await createGenerateFunctionFromModel(modelToUse);
198
+ searchEngine.setGenerateFunction(generateFn);
199
+ console.log('✅ Generator initialized');
200
+ console.log('');
201
+ }
202
+ catch (error) {
203
+ console.error('❌ [EXPERIMENTAL] Failed to initialize generator:', error instanceof Error ? error.message : 'Unknown error');
204
+ console.error(' Continuing without generation...');
205
+ console.error('');
206
+ }
207
+ }
208
+ // Set generation options if generator is ready
209
+ if (generateFn && generateResponse && !isImage) {
210
+ searchOptions.generateResponse = true;
211
+ searchOptions.generationOptions = {
212
+ maxTokens: maxGenerationTokens,
213
+ temperature: generationTemperature,
214
+ maxChunksForContext: maxChunksForContext
215
+ };
216
+ }
167
217
  // Perform search
168
218
  const startTime = Date.now();
169
219
  let results;
220
+ let generationResult;
170
221
  if (isImage && embedder) {
171
222
  // Image-based search: embed the image and search with the vector
172
223
  console.log('Embedding image...');
@@ -174,8 +225,14 @@ export async function runSearch(query, options = {}) {
174
225
  console.log('Searching with image embedding...');
175
226
  results = await searchEngine.searchWithVector(imageEmbedding.vector, searchOptions);
176
227
  }
228
+ else if (generateResponse && generateFn) {
229
+ // Text-based search with generation
230
+ const searchResult = await searchEngine.searchWithGeneration(query, searchOptions);
231
+ results = searchResult.results;
232
+ generationResult = searchResult.generation;
233
+ }
177
234
  else {
178
- // Text-based search
235
+ // Standard text-based search
179
236
  results = await searchEngine.search(query, searchOptions);
180
237
  }
181
238
  const searchTime = Date.now() - startTime;
@@ -216,6 +273,21 @@ export async function runSearch(query, options = {}) {
216
273
  }
217
274
  console.log('');
218
275
  });
276
+ // Display generated response if available (experimental)
277
+ if (generationResult) {
278
+ console.log('─'.repeat(50));
279
+ console.log('🤖 Generated Response [EXPERIMENTAL]');
280
+ console.log(`Model: ${generationResult.modelUsed}`);
281
+ console.log('─'.repeat(50));
282
+ console.log('');
283
+ console.log(generationResult.response);
284
+ console.log('');
285
+ console.log('─'.repeat(50));
286
+ console.log(`⏱️ Generation: ${(generationResult.generationTimeMs / 1000).toFixed(1)}s | ` +
287
+ `📊 ${generationResult.tokensUsed} tokens | ` +
288
+ `📄 ${generationResult.chunksUsedForContext} chunks used` +
289
+ (generationResult.truncated ? ' (context truncated)' : ''));
290
+ }
219
291
  // Show search statistics
220
292
  const stats = await searchEngine.getStats();
221
293
  console.log('─'.repeat(50));
@@ -233,6 +305,9 @@ export async function runSearch(query, options = {}) {
233
305
  else {
234
306
  console.log('Reranking: disabled');
235
307
  }
308
+ if (generationResult) {
309
+ console.log('Generation: enabled [EXPERIMENTAL]');
310
+ }
236
311
  }
237
312
  }
238
313
  finally {
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Launch the UI server
3
+ */
4
+ export declare function runUI(options?: any): Promise<void>;
5
+ //# sourceMappingURL=ui-server.d.ts.map
@@ -0,0 +1,152 @@
1
+ import { fileURLToPath } from 'url';
2
+ import { dirname, join } from 'path';
3
+ import { spawn } from 'child_process';
4
+ import fs from 'fs';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = dirname(__filename);
7
+ /**
8
+ * Get the project root directory
9
+ * When built, CLI is at dist/esm/cli/ui-server.js, so go up 3 levels
10
+ * When running from source, CLI is at src/cli/ui-server.ts, so go up 2 levels
11
+ */
12
+ function getProjectRoot() {
13
+ // Try going up 3 levels first (for built version)
14
+ const builtPath = join(__dirname, '../../..');
15
+ if (fs.existsSync(join(builtPath, 'package.json'))) {
16
+ return builtPath;
17
+ }
18
+ // Fallback: go up 2 levels (for source execution)
19
+ return join(__dirname, '../..');
20
+ }
21
+ /**
22
+ * Launch the UI server
23
+ */
24
+ export async function runUI(options = {}) {
25
+ const port = options.port || 3000;
26
+ const backendPort = options.backendPort || 3001;
27
+ console.log('🚀 Launching RAG-lite TS UI...');
28
+ // Resolve UI paths from project root
29
+ const projectRoot = getProjectRoot();
30
+ const backendBuiltPath = join(projectRoot, 'ui', 'backend', 'dist', 'index.js');
31
+ const backendSourcePath = join(projectRoot, 'ui', 'backend', 'src', 'index.ts');
32
+ const frontendBuiltPath = join(projectRoot, 'ui', 'frontend', 'dist');
33
+ const frontendSourcePath = join(projectRoot, 'ui', 'frontend');
34
+ // Check if built files exist
35
+ const useBuiltBackend = fs.existsSync(backendBuiltPath);
36
+ const useBuiltFrontend = fs.existsSync(frontendBuiltPath);
37
+ if (!useBuiltBackend && !fs.existsSync(backendSourcePath)) {
38
+ console.error(`❌ UI backend not found at: ${backendSourcePath}`);
39
+ console.error(' Make sure the UI is set up in the ui/ directory.');
40
+ process.exit(1);
41
+ }
42
+ if (!useBuiltFrontend && !fs.existsSync(frontendSourcePath)) {
43
+ console.error(`❌ UI frontend not found at: ${frontendSourcePath}`);
44
+ console.error(' Make sure the UI is set up in the ui/ directory.');
45
+ process.exit(1);
46
+ }
47
+ // Pass the working directory where 'raglite ui' was called to the backend
48
+ const workingDir = process.cwd();
49
+ // Built mode: single server on port (UI + API). Dev mode: backend on backendPort, frontend on port.
50
+ const effectiveBackendPort = useBuiltFrontend ? port : backendPort;
51
+ console.log(`📡 Starting backend on port ${effectiveBackendPort}...`);
52
+ // Start backend server - use built version if available
53
+ const backendCommand = useBuiltBackend ? 'node' : 'npx';
54
+ const backendArgs = useBuiltBackend
55
+ ? [backendBuiltPath]
56
+ : ['tsx', backendSourcePath];
57
+ const backendProcess = spawn(backendCommand, backendArgs, {
58
+ stdio: 'pipe',
59
+ env: {
60
+ ...process.env,
61
+ PORT: effectiveBackendPort.toString(),
62
+ RAG_WORKING_DIR: workingDir,
63
+ UI_FRONTEND_DIST: useBuiltFrontend ? frontendBuiltPath : undefined
64
+ },
65
+ shell: true
66
+ });
67
+ backendProcess.on('error', (err) => {
68
+ console.error('❌ Failed to start backend process:', err);
69
+ process.exit(1);
70
+ });
71
+ // Forward backend output with prefix
72
+ backendProcess.stdout?.on('data', (data) => {
73
+ process.stdout.write(`[Backend] ${data}`);
74
+ });
75
+ backendProcess.stderr?.on('data', (data) => {
76
+ process.stderr.write(`[Backend] ${data}`);
77
+ });
78
+ // Only start frontend dev server if built version doesn't exist
79
+ let frontendProcess = null;
80
+ if (!useBuiltFrontend) {
81
+ console.log(`🎨 Starting frontend dev server on port ${port}...`);
82
+ frontendProcess = spawn('npm', ['run', 'dev'], {
83
+ cwd: frontendSourcePath,
84
+ stdio: 'pipe',
85
+ env: {
86
+ ...process.env,
87
+ VITE_API_URL: `http://localhost:${effectiveBackendPort}`
88
+ },
89
+ shell: true
90
+ });
91
+ frontendProcess.on('error', (err) => {
92
+ console.error('❌ Failed to start frontend process:', err);
93
+ backendProcess.kill();
94
+ process.exit(1);
95
+ });
96
+ // Forward frontend output with prefix
97
+ frontendProcess.stdout?.on('data', (data) => {
98
+ process.stdout.write(`[Frontend] ${data}`);
99
+ });
100
+ frontendProcess.stderr?.on('data', (data) => {
101
+ process.stderr.write(`[Frontend] ${data}`);
102
+ });
103
+ }
104
+ else {
105
+ console.log(`🎨 Using built frontend from ${frontendBuiltPath}`);
106
+ console.log(` Frontend will be served by backend on port ${effectiveBackendPort}`);
107
+ }
108
+ // Wait a bit for servers to start
109
+ await new Promise(resolve => setTimeout(resolve, 2000));
110
+ console.log(`\n✨ UI Access:`);
111
+ if (useBuiltFrontend) {
112
+ console.log(` Frontend & Backend: http://localhost:${port}`);
113
+ }
114
+ else {
115
+ console.log(` Frontend: http://localhost:${port}`);
116
+ console.log(` Backend: http://localhost:${effectiveBackendPort}`);
117
+ }
118
+ console.log(`\n💡 Press Ctrl+C to stop both servers\n`);
119
+ // Keep the process alive and handle cleanup
120
+ return new Promise((resolve) => {
121
+ const cleanup = () => {
122
+ console.log('\n🛑 Shutting down servers...');
123
+ backendProcess.kill();
124
+ if (frontendProcess) {
125
+ frontendProcess.kill();
126
+ }
127
+ resolve();
128
+ };
129
+ process.on('SIGINT', cleanup);
130
+ process.on('SIGTERM', cleanup);
131
+ // Handle process exits
132
+ backendProcess.on('exit', (code) => {
133
+ if (code !== 0 && code !== null) {
134
+ console.error(`\n❌ Backend process exited with code ${code}`);
135
+ if (frontendProcess) {
136
+ frontendProcess.kill();
137
+ }
138
+ resolve();
139
+ }
140
+ });
141
+ if (frontendProcess) {
142
+ frontendProcess.on('exit', (code) => {
143
+ if (code !== 0 && code !== null) {
144
+ console.error(`\n❌ Frontend process exited with code ${code}`);
145
+ backendProcess.kill();
146
+ resolve();
147
+ }
148
+ });
149
+ }
150
+ });
151
+ }
152
+ //# sourceMappingURL=ui-server.js.map
package/dist/esm/cli.js CHANGED
@@ -6,8 +6,18 @@ import { EXIT_CODES, ConfigurationError } from './core/config.js';
6
6
  // Get package.json for version info
7
7
  const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = dirname(__filename);
9
- const packageJsonPath = join(__dirname, '..', 'package.json');
10
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
9
+ // When built, CLI is at dist/esm/cli.js, so go up two levels to root
10
+ // When running from source, CLI is at src/cli.ts, so go up one level to root
11
+ const packageJsonPath = join(__dirname, '..', '..', 'package.json');
12
+ let packageJson;
13
+ try {
14
+ packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
15
+ }
16
+ catch {
17
+ // Fallback: try one level up (for source execution)
18
+ const fallbackPath = join(__dirname, '..', 'package.json');
19
+ packageJson = JSON.parse(readFileSync(fallbackPath, 'utf-8'));
20
+ }
11
21
  /**
12
22
  * Display version information
13
23
  */
@@ -28,6 +38,7 @@ Usage:
28
38
  Commands:
29
39
  ingest <path> Ingest documents from file or directory
30
40
  search <query> Search indexed documents (text or image)
41
+ ui Launch the web interface
31
42
  rebuild Rebuild the vector index
32
43
  version Show version information
33
44
  help Show this help message
@@ -43,6 +54,8 @@ Examples:
43
54
  raglite search "red car" --content-type image # Search only image results
44
55
  raglite search ./photo.jpg # Search with image (multimodal mode only)
45
56
  raglite search ./image.png --top-k 5 # Find similar images
57
+ raglite search "How does auth work?" --generate # [EXPERIMENTAL] Generate AI response
58
+ raglite ui # Launch web interface
46
59
 
47
60
  raglite rebuild # Rebuild the entire index
48
61
 
@@ -52,10 +65,17 @@ Options for search:
52
65
  --no-rerank Disable reranking
53
66
  --content-type <type> Filter results by content type: 'text', 'image', or 'all' (default: all)
54
67
 
68
+ [EXPERIMENTAL] AI Response Generation (text mode only):
69
+ --generate Generate an AI response from search results
70
+ --generator <model> Generator model to use (default: SmolLM2-135M-Instruct)
71
+ --max-tokens <n> Maximum tokens to generate (default: 512)
72
+ --temperature <n> Sampling temperature 0-1 (default: 0.1)
73
+ --max-chunks <n> Maximum chunks for context (default: 3 for 135M, 5 for 360M)
74
+
55
75
  Options for ingest:
56
76
  --model <name> Use specific embedding model
57
77
  --mode <mode> Processing mode: 'text' (default) or 'multimodal'
58
- --rebuild-if-needed Automatically rebuild if model mismatch detected (WARNING: rebuilds entire index)
78
+ --force-rebuild Wipe DB+index and rebuild from scratch (DESTRUCTIVE)
59
79
  --path-strategy <strategy> Path storage strategy: 'relative' (default) or 'absolute'
60
80
  --path-base <path> Base directory for relative paths (defaults to current directory)
61
81
 
@@ -71,6 +91,12 @@ Available reranking strategies (multimodal mode):
71
91
  text-derived Use image-to-text conversion + cross-encoder (default)
72
92
  disabled No reranking, use vector similarity only
73
93
 
94
+ [EXPERIMENTAL] Available generator models:
95
+ HuggingFaceTB/SmolLM2-135M-Instruct (balanced, recommended default, uses top 3 chunks)
96
+ HuggingFaceTB/SmolLM2-360M-Instruct (higher quality, slower, uses top 5 chunks)
97
+
98
+ Note: Generation requires reranking (--rerank is automatically enabled with --generate)
99
+
74
100
  For more information, visit: https://github.com/your-repo/rag-lite-ts
75
101
  `);
76
102
  }
@@ -111,8 +137,12 @@ function parseArgs() {
111
137
  else if (optionName === 'no-rerank') {
112
138
  options.rerank = false;
113
139
  }
114
- else if (optionName === 'rebuild-if-needed') {
115
- options.rebuildIfNeeded = true;
140
+ else if (optionName === 'force-rebuild') {
141
+ options.forceRebuild = true;
142
+ }
143
+ else if (optionName === 'generate') {
144
+ // Handle --generate flag for experimental response generation
145
+ options.generate = true;
116
146
  }
117
147
  else if (optionName === 'help') {
118
148
  return { command: 'help', args: [], options: {} };
@@ -124,7 +154,16 @@ function parseArgs() {
124
154
  // Handle options with values
125
155
  const nextArg = args[i + 1];
126
156
  if (nextArg && !nextArg.startsWith('--')) {
127
- options[optionName] = nextArg;
157
+ // Parse numeric values for specific options
158
+ if (optionName === 'max-tokens' || optionName === 'top-k' || optionName === 'max-chunks') {
159
+ options[optionName] = parseInt(nextArg, 10);
160
+ }
161
+ else if (optionName === 'temperature') {
162
+ options[optionName] = parseFloat(nextArg);
163
+ }
164
+ else {
165
+ options[optionName] = nextArg;
166
+ }
128
167
  i++; // Skip the next argument as it's the value
129
168
  }
130
169
  else {
@@ -169,7 +208,7 @@ function validateArgs(command, args, options) {
169
208
  console.error('Options:');
170
209
  console.error(' --model <name> Use specific embedding model');
171
210
  console.error(' --mode <mode> Processing mode: text (default) or multimodal');
172
- console.error(' --rebuild-if-needed Automatically rebuild if model mismatch detected');
211
+ console.error(' --force-rebuild Wipe DB+index and rebuild from scratch (DESTRUCTIVE)');
173
212
  console.error('');
174
213
  console.error('The path can be either a file (.md or .txt) or a directory.');
175
214
  process.exit(EXIT_CODES.INVALID_ARGUMENTS);
@@ -201,6 +240,9 @@ function validateArgs(command, args, options) {
201
240
  case 'rebuild':
202
241
  // No arguments required
203
242
  break;
243
+ case 'ui':
244
+ // No arguments required
245
+ break;
204
246
  case 'version':
205
247
  // No validation needed
206
248
  break;
@@ -412,6 +454,10 @@ async function main() {
412
454
  const { runRebuild } = await import('./cli/indexer.js');
413
455
  await runRebuild();
414
456
  break;
457
+ case 'ui':
458
+ const { runUI } = await import('./cli/ui-server.js');
459
+ await runUI(options);
460
+ break;
415
461
  default:
416
462
  console.error(`Error: Unknown command '${command}'`);
417
463
  process.exit(1);
@@ -0,0 +1,97 @@
1
+ /**
2
+ * CORE MODULE — Abstract Base Generator
3
+ *
4
+ * Provides model-agnostic base functionality for all generator implementations.
5
+ * This is an abstract base class, not a concrete implementation.
6
+ *
7
+ * ARCHITECTURAL NOTE:
8
+ * Similar to BaseUniversalEmbedder, this class provides shared infrastructure:
9
+ * - Model lifecycle management (loading, cleanup, disposal)
10
+ * - Token budget management
11
+ * - Error handling with helpful messages
12
+ * - Common utility methods
13
+ *
14
+ * IMPLEMENTATION LAYERS:
15
+ * - Text: InstructGenerator extends this class (SmolLM2-Instruct)
16
+ * - Text: CausalLMGenerator extends this class (DistilGPT2)
17
+ *
18
+ * @experimental This feature is experimental and may change in future versions.
19
+ */
20
+ import type { ResponseGenerator, GeneratorModelInfo, GeneratorModelType, GenerationRequest, GenerationResult, GeneratorCreationOptions } from './response-generator.js';
21
+ import { GenerationError } from './response-generator.js';
22
+ /**
23
+ * Abstract base class for response generators
24
+ * Provides common functionality and lifecycle management
25
+ */
26
+ export declare abstract class BaseResponseGenerator implements ResponseGenerator {
27
+ readonly modelName: string;
28
+ protected _isLoaded: boolean;
29
+ protected _modelInfo: GeneratorModelInfo;
30
+ protected _options: GeneratorCreationOptions;
31
+ constructor(modelName: string, options?: GeneratorCreationOptions);
32
+ get modelType(): GeneratorModelType;
33
+ get maxContextLength(): number;
34
+ get maxOutputLength(): number;
35
+ isLoaded(): boolean;
36
+ getModelInfo(): GeneratorModelInfo;
37
+ /**
38
+ * Load the model - must be implemented by subclasses
39
+ */
40
+ abstract loadModel(): Promise<void>;
41
+ /**
42
+ * Generate text using the model - must be implemented by subclasses
43
+ * @param prompt - The formatted prompt string
44
+ * @param options - Generation options
45
+ * @returns Generated text
46
+ */
47
+ protected abstract generateText(prompt: string, options: {
48
+ maxTokens: number;
49
+ temperature: number;
50
+ topP: number;
51
+ topK: number;
52
+ repetitionPenalty: number;
53
+ stopSequences: string[];
54
+ }): Promise<{
55
+ text: string;
56
+ promptTokens: number;
57
+ completionTokens: number;
58
+ finishReason: 'complete' | 'length' | 'stop_sequence' | 'error';
59
+ }>;
60
+ /**
61
+ * Clean up resources - must be implemented by subclasses
62
+ */
63
+ abstract cleanup(): Promise<void>;
64
+ /**
65
+ * Generate a response based on query and retrieved chunks
66
+ * This method orchestrates the generation pipeline
67
+ */
68
+ generate(request: GenerationRequest): Promise<GenerationResult>;
69
+ /**
70
+ * Validate that the model is loaded before operations
71
+ */
72
+ protected ensureLoaded(): void;
73
+ /**
74
+ * Clean up response text by removing artifacts
75
+ */
76
+ protected cleanResponseText(text: string): string;
77
+ /**
78
+ * Log model loading progress
79
+ */
80
+ protected logModelLoading(stage: string, details?: string): void;
81
+ /**
82
+ * Handle model loading errors with helpful messages
83
+ */
84
+ protected handleLoadingError(error: Error): GenerationError;
85
+ }
86
+ /**
87
+ * Extended options for generator instances
88
+ */
89
+ export interface GeneratorOptions extends GeneratorCreationOptions {
90
+ /** Log level for debugging */
91
+ logLevel?: 'debug' | 'info' | 'warn' | 'error' | 'silent';
92
+ }
93
+ /**
94
+ * Create generator options with defaults
95
+ */
96
+ export declare function createGeneratorOptions(options?: Partial<GeneratorOptions>): GeneratorOptions;
97
+ //# sourceMappingURL=abstract-generator.d.ts.map