@retrivora-ai/rag-engine 0.4.5 → 1.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.
- package/README.md +32 -57
- package/dist/{ChromaDBProvider-GI7TB7GJ.mjs → ChromaDBProvider-APQVJ5F7.mjs} +2 -2
- package/dist/{DocumentChunker-3yElxTO3.d.mts → DocumentChunker-C-sCZPhi.d.mts} +6 -6
- package/dist/{DocumentChunker-3yElxTO3.d.ts → DocumentChunker-C-sCZPhi.d.ts} +6 -6
- package/dist/{MilvusProvider-WDVTFB7D.mjs → MilvusProvider-35US67MS.mjs} +2 -2
- package/dist/{MongoDBProvider-RE3Q5S5B.mjs → MongoDBProvider-COVYZDP6.mjs} +2 -2
- package/dist/{PineconeProvider-BE2JWSPD.mjs → PineconeProvider-AWFJQDZL.mjs} +2 -2
- package/dist/{PostgreSQLProvider-5HHTK4SU.mjs → PostgreSQLProvider-IEYRJ7XJ.mjs} +2 -2
- package/dist/{QdrantProvider-XVDVBNIG.mjs → QdrantProvider-M6TQYZRO.mjs} +2 -2
- package/dist/{RagConfig-BgRDL9Vy.d.mts → RagConfig-DRJO4hGU.d.mts} +12 -1
- package/dist/{RagConfig-BgRDL9Vy.d.ts → RagConfig-DRJO4hGU.d.ts} +12 -1
- package/dist/{RedisProvider-EK2R2PQH.mjs → RedisProvider-3G5PBLZ4.mjs} +2 -2
- package/dist/{SimpleGraphProvider-M6T7SE7D.mjs → SimpleGraphProvider-UK7DJW37.mjs} +1 -1
- package/dist/{UniversalVectorProvider-YIDRX6VT.mjs → UniversalVectorProvider-FYQ3B2PW.mjs} +3 -3
- package/dist/{WeaviateProvider-4CAPQ7UY.mjs → WeaviateProvider-ITHO36IL.mjs} +2 -2
- package/dist/{chunk-5KNBWQM6.mjs → chunk-4A47RCG2.mjs} +5 -1
- package/dist/{chunk-EDLTMSNY.mjs → chunk-67AJ6SMD.mjs} +1 -1
- package/dist/{chunk-PQKTC73Y.mjs → chunk-7SOSCZGS.mjs} +67 -6
- package/dist/{chunk-LJWWPTWE.mjs → chunk-FLOSGE6A.mjs} +76 -14
- package/dist/{chunk-H6RKMU7W.mjs → chunk-NXUCKY5L.mjs} +1 -1
- package/dist/{chunk-KTS3LLHY.mjs → chunk-OOQXNLXD.mjs} +5 -5
- package/dist/{chunk-PRC5CZIZ.mjs → chunk-P4HAQ7KB.mjs} +1184 -1359
- package/dist/chunk-QMIKLALV.mjs +57 -0
- package/dist/{chunk-3QWAK3RZ.mjs → chunk-TYHTZIDP.mjs} +6 -2
- package/dist/{chunk-GQT5LF4G.mjs → chunk-U6KHVZLF.mjs} +2 -2
- package/dist/{chunk-RK2UDJA2.mjs → chunk-WGSZNY3X.mjs} +1 -1
- package/dist/{chunk-XCNXPECE.mjs → chunk-ZNBKHNJ4.mjs} +55 -1
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +1415 -1391
- package/dist/handlers/index.mjs +3 -3
- package/dist/index-CrGMwXfO.d.ts +112 -0
- package/dist/index-v669iV-k.d.mts +112 -0
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +2 -2
- package/dist/server.d.mts +104 -158
- package/dist/server.d.ts +104 -158
- package/dist/server.js +1414 -1390
- package/dist/server.mjs +12 -12
- package/package.json +5 -1
- package/src/config/RagConfig.ts +7 -0
- package/src/core/ConfigValidator.ts +66 -492
- package/src/core/LangChainAgent.ts +78 -0
- package/src/core/Pipeline.ts +210 -240
- package/src/core/ProviderHealthCheck.ts +35 -406
- package/src/core/ProviderInterfaces.ts +37 -0
- package/src/core/ProviderRegistry.ts +70 -55
- package/src/core/QueryProcessor.ts +173 -0
- package/src/llm/ILLMProvider.ts +10 -0
- package/src/llm/LLMFactory.ts +33 -13
- package/src/llm/providers/AnthropicProvider.ts +55 -15
- package/src/llm/providers/GeminiProvider.ts +51 -0
- package/src/llm/providers/OllamaProvider.ts +100 -15
- package/src/llm/providers/OpenAIProvider.ts +60 -11
- package/src/providers/vectordb/BaseVectorProvider.ts +11 -0
- package/src/providers/vectordb/MilvusProvider.ts +4 -0
- package/src/providers/vectordb/MongoDBProvider.ts +72 -8
- package/src/providers/vectordb/PineconeProvider.ts +60 -5
- package/src/providers/vectordb/PostgreSQLProvider.ts +84 -14
- package/src/providers/vectordb/QdrantProvider.ts +4 -0
- package/src/providers/vectordb/WeaviateProvider.ts +8 -4
- package/src/rag/DocumentChunker.ts +15 -19
- package/src/rag/LlamaIndexIngestor.ts +61 -0
- package/src/rag/Reranker.ts +20 -0
- package/src/server.ts +1 -1
- package/src/types/index.ts +9 -0
- package/dist/chunk-FWCSY2DS.mjs +0 -37
- package/dist/index-7qeLTPBL.d.mts +0 -114
- package/dist/index-DowY4_K0.d.ts +0 -114
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ConfigValidator.ts — Comprehensive configuration validation.
|
|
3
|
-
*
|
|
4
|
-
* Validates RagConfig against provider requirements and best practices.
|
|
5
|
-
* Returns detailed errors for misconfiguration.
|
|
6
|
-
*
|
|
7
|
-
* Key invariant: option keys validated here MUST match the keys each
|
|
8
|
-
* Provider constructor reads. See each provider's constructor for the
|
|
9
|
-
* canonical option names.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
1
|
import { RagConfig, VectorDBConfig, LLMConfig, EmbeddingConfig } from '../config/RagConfig';
|
|
13
2
|
import {
|
|
14
|
-
UI_VISUAL_STYLES,
|
|
15
3
|
UI_BORDER_RADIUS_OPTIONS,
|
|
16
4
|
} from '../config/constants';
|
|
5
|
+
import { ProviderRegistry } from './ProviderRegistry';
|
|
6
|
+
import { LLMFactory } from '../llm/LLMFactory';
|
|
17
7
|
|
|
18
8
|
export interface ValidationError {
|
|
19
9
|
field: string;
|
|
@@ -22,12 +12,15 @@ export interface ValidationError {
|
|
|
22
12
|
severity: 'error' | 'warning';
|
|
23
13
|
}
|
|
24
14
|
|
|
15
|
+
/**
|
|
16
|
+
* ConfigValidator.ts — Comprehensive configuration validation.
|
|
17
|
+
* Uses a pluggable architecture to delegate provider-specific checks.
|
|
18
|
+
*/
|
|
25
19
|
export class ConfigValidator {
|
|
26
20
|
/**
|
|
27
21
|
* Validates the entire RagConfig object.
|
|
28
|
-
* Returns an array of validation errors. Empty array = valid config.
|
|
29
22
|
*/
|
|
30
|
-
static validate(config: RagConfig): ValidationError[] {
|
|
23
|
+
static async validate(config: RagConfig): Promise<ValidationError[]> {
|
|
31
24
|
const errors: ValidationError[] = [];
|
|
32
25
|
|
|
33
26
|
if (!config.projectId) {
|
|
@@ -38,11 +31,11 @@ export class ConfigValidator {
|
|
|
38
31
|
});
|
|
39
32
|
}
|
|
40
33
|
|
|
41
|
-
errors.push(...this.validateVectorDbConfig(config.vectorDb));
|
|
42
|
-
errors.push(...this.validateLLMConfig(config.llm));
|
|
34
|
+
errors.push(...(await this.validateVectorDbConfig(config.vectorDb)));
|
|
35
|
+
errors.push(...(await this.validateLLMConfig(config.llm)));
|
|
43
36
|
|
|
44
37
|
if (config.embedding) {
|
|
45
|
-
errors.push(...this.validateEmbeddingConfig(config.embedding));
|
|
38
|
+
errors.push(...(await this.validateEmbeddingConfig(config.embedding)));
|
|
46
39
|
} else if (config.llm.provider === 'anthropic') {
|
|
47
40
|
errors.push({
|
|
48
41
|
field: 'embedding',
|
|
@@ -63,472 +56,112 @@ export class ConfigValidator {
|
|
|
63
56
|
return errors;
|
|
64
57
|
}
|
|
65
58
|
|
|
66
|
-
private static validateVectorDbConfig(config: VectorDBConfig): ValidationError[] {
|
|
59
|
+
private static async validateVectorDbConfig(config: VectorDBConfig): Promise<ValidationError[]> {
|
|
67
60
|
const errors: ValidationError[] = [];
|
|
68
61
|
|
|
69
62
|
if (!config.provider) {
|
|
70
|
-
errors.push({
|
|
71
|
-
field: 'vectorDb.provider',
|
|
72
|
-
message: 'Vector database provider is required',
|
|
73
|
-
severity: 'error',
|
|
74
|
-
});
|
|
63
|
+
errors.push({ field: 'vectorDb.provider', message: 'Vector database provider is required', severity: 'error' });
|
|
75
64
|
return errors;
|
|
76
65
|
}
|
|
77
66
|
|
|
78
67
|
if (!config.indexName) {
|
|
79
|
-
errors.push({
|
|
80
|
-
field: 'vectorDb.indexName',
|
|
81
|
-
message: 'Vector database index name is required',
|
|
82
|
-
severity: 'error',
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
switch (config.provider) {
|
|
87
|
-
case 'pinecone':
|
|
88
|
-
errors.push(...this.validatePineconeConfig(config));
|
|
89
|
-
break;
|
|
90
|
-
case 'pgvector':
|
|
91
|
-
case 'postgresql':
|
|
92
|
-
errors.push(...this.validatePostgresConfig(config));
|
|
93
|
-
break;
|
|
94
|
-
case 'mongodb':
|
|
95
|
-
errors.push(...this.validateMongoDBConfig(config));
|
|
96
|
-
break;
|
|
97
|
-
case 'milvus':
|
|
98
|
-
errors.push(...this.validateMilvusConfig(config));
|
|
99
|
-
break;
|
|
100
|
-
case 'qdrant':
|
|
101
|
-
errors.push(...this.validateQdrantConfig(config));
|
|
102
|
-
break;
|
|
103
|
-
case 'chromadb':
|
|
104
|
-
errors.push(...this.validateChromaDBConfig(config));
|
|
105
|
-
break;
|
|
106
|
-
case 'redis':
|
|
107
|
-
errors.push(...this.validateRedisConfig(config));
|
|
108
|
-
break;
|
|
109
|
-
case 'weaviate':
|
|
110
|
-
errors.push(...this.validateWeaviateConfig(config));
|
|
111
|
-
break;
|
|
112
|
-
case 'universal_rest':
|
|
113
|
-
case 'rest':
|
|
114
|
-
errors.push(...this.validateRestConfig(config));
|
|
115
|
-
break;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
return errors;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Pinecone — only needs apiKey (environment was removed in SDK v7+).
|
|
123
|
-
* Options key: { apiKey: string }
|
|
124
|
-
*/
|
|
125
|
-
private static validatePineconeConfig(config: VectorDBConfig): ValidationError[] {
|
|
126
|
-
const errors: ValidationError[] = [];
|
|
127
|
-
const opts = config.options as Record<string, unknown>;
|
|
128
|
-
|
|
129
|
-
if (!opts.apiKey) {
|
|
130
|
-
errors.push({
|
|
131
|
-
field: 'vectorDb.options.apiKey',
|
|
132
|
-
message: 'Pinecone API key is required',
|
|
133
|
-
suggestion: 'Set PINECONE_API_KEY environment variable',
|
|
134
|
-
severity: 'error',
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return errors;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* PostgreSQL / pgvector — needs a connection string.
|
|
143
|
-
* Options key: { connectionString: string }
|
|
144
|
-
*/
|
|
145
|
-
private static validatePostgresConfig(config: VectorDBConfig): ValidationError[] {
|
|
146
|
-
const errors: ValidationError[] = [];
|
|
147
|
-
const opts = config.options as Record<string, unknown>;
|
|
148
|
-
|
|
149
|
-
if (!opts.connectionString) {
|
|
150
|
-
errors.push({
|
|
151
|
-
field: 'vectorDb.options.connectionString',
|
|
152
|
-
message: 'PostgreSQL connection string is required',
|
|
153
|
-
suggestion: 'Set PGVECTOR_CONNECTION_STRING environment variable',
|
|
154
|
-
severity: 'error',
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (opts.tables && typeof opts.tables !== 'string' && !Array.isArray(opts.tables)) {
|
|
159
|
-
errors.push({
|
|
160
|
-
field: 'vectorDb.options.tables',
|
|
161
|
-
message: 'PostgreSQL tables must be a string or a string array',
|
|
162
|
-
severity: 'error',
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
if (opts.searchFields && typeof opts.searchFields !== 'string' && !Array.isArray(opts.searchFields)) {
|
|
167
|
-
errors.push({
|
|
168
|
-
field: 'vectorDb.options.searchFields',
|
|
169
|
-
message: 'PostgreSQL searchFields must be a string or a string array',
|
|
170
|
-
severity: 'error',
|
|
171
|
-
});
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return errors;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* MongoDB — needs uri, database, and collection.
|
|
179
|
-
* Options keys: { uri: string, database: string, collection: string }
|
|
180
|
-
*/
|
|
181
|
-
private static validateMongoDBConfig(config: VectorDBConfig): ValidationError[] {
|
|
182
|
-
const errors: ValidationError[] = [];
|
|
183
|
-
const opts = config.options as Record<string, unknown>;
|
|
184
|
-
|
|
185
|
-
if (!opts.uri) {
|
|
186
|
-
errors.push({
|
|
187
|
-
field: 'vectorDb.options.uri',
|
|
188
|
-
message: 'MongoDB connection URI is required',
|
|
189
|
-
suggestion: 'Set MONGODB_URI environment variable',
|
|
190
|
-
severity: 'error',
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (!opts.database) {
|
|
195
|
-
errors.push({
|
|
196
|
-
field: 'vectorDb.options.database',
|
|
197
|
-
message: 'MongoDB database name is required',
|
|
198
|
-
suggestion: 'Set MONGODB_DB environment variable',
|
|
199
|
-
severity: 'error',
|
|
200
|
-
});
|
|
68
|
+
errors.push({ field: 'vectorDb.indexName', message: 'Vector database index name is required', severity: 'error' });
|
|
201
69
|
}
|
|
202
70
|
|
|
203
|
-
if
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
71
|
+
// Delegate to pluggable validator if available
|
|
72
|
+
const validator = await ProviderRegistry.getVectorValidator(config.provider);
|
|
73
|
+
if (validator) {
|
|
74
|
+
errors.push(...validator.validate(config as unknown as Record<string, unknown>));
|
|
75
|
+
} else {
|
|
76
|
+
// Fallback for non-migrated providers
|
|
77
|
+
this.fallbackVectorValidation(config, errors);
|
|
210
78
|
}
|
|
211
79
|
|
|
212
80
|
return errors;
|
|
213
81
|
}
|
|
214
82
|
|
|
215
|
-
|
|
216
|
-
* Milvus — accepts baseUrl OR uri (preferred) OR host+port.
|
|
217
|
-
* MilvusProvider reads opts.baseUrl ?? opts.uri.
|
|
218
|
-
* Options keys: { baseUrl?: string, uri?: string, host?: string, port?: number }
|
|
219
|
-
*/
|
|
220
|
-
private static validateMilvusConfig(config: VectorDBConfig): ValidationError[] {
|
|
83
|
+
private static async validateLLMConfig(config: LLMConfig): Promise<ValidationError[]> {
|
|
221
84
|
const errors: ValidationError[] = [];
|
|
222
|
-
const opts = config.options as Record<string, unknown>;
|
|
223
85
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (!hasBaseUrl && !hasHostPort) {
|
|
228
|
-
errors.push({
|
|
229
|
-
field: 'vectorDb.options.baseUrl',
|
|
230
|
-
message: 'Milvus connection is required: provide baseUrl (e.g., "http://localhost:19530") or host + port',
|
|
231
|
-
suggestion: 'Set MILVUS_URL environment variable',
|
|
232
|
-
severity: 'error',
|
|
233
|
-
});
|
|
86
|
+
if (!config.provider) {
|
|
87
|
+
errors.push({ field: 'llm.provider', message: 'LLM provider is required', severity: 'error' });
|
|
88
|
+
return errors;
|
|
234
89
|
}
|
|
235
90
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
* Options keys: { baseUrl: string, apiKey?: string }
|
|
242
|
-
*/
|
|
243
|
-
private static validateQdrantConfig(config: VectorDBConfig): ValidationError[] {
|
|
244
|
-
const errors: ValidationError[] = [];
|
|
245
|
-
const opts = config.options as Record<string, unknown>;
|
|
246
|
-
|
|
247
|
-
if (!opts.baseUrl && !opts.url) {
|
|
248
|
-
errors.push({
|
|
249
|
-
field: 'vectorDb.options.baseUrl',
|
|
250
|
-
message: 'Qdrant base URL is required',
|
|
251
|
-
suggestion: 'Set QDRANT_URL environment variable (e.g., "http://localhost:6333")',
|
|
252
|
-
severity: 'error',
|
|
253
|
-
});
|
|
91
|
+
const validator = LLMFactory.getValidator(config.provider);
|
|
92
|
+
if (validator) {
|
|
93
|
+
errors.push(...validator.validate(config as unknown as Record<string, unknown>));
|
|
94
|
+
} else {
|
|
95
|
+
this.fallbackLLMValidation(config, errors);
|
|
254
96
|
}
|
|
255
97
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* ChromaDB — accepts baseUrl OR host.
|
|
261
|
-
* ChromaDBProvider reads opts.baseUrl.
|
|
262
|
-
* Options keys: { baseUrl?: string, host?: string, port?: number }
|
|
263
|
-
*/
|
|
264
|
-
private static validateChromaDBConfig(config: VectorDBConfig): ValidationError[] {
|
|
265
|
-
const errors: ValidationError[] = [];
|
|
266
|
-
const opts = config.options as Record<string, unknown>;
|
|
267
|
-
|
|
268
|
-
if (!opts.baseUrl && !opts.host) {
|
|
269
|
-
errors.push({
|
|
270
|
-
field: 'vectorDb.options.baseUrl',
|
|
271
|
-
message: 'ChromaDB connection is required: provide baseUrl (e.g., "http://localhost:8000") or host',
|
|
272
|
-
suggestion: 'Set CHROMADB_URL environment variable',
|
|
273
|
-
severity: 'error',
|
|
274
|
-
});
|
|
98
|
+
if (config.temperature !== undefined && (config.temperature < 0 || config.temperature > 2)) {
|
|
99
|
+
errors.push({ field: 'llm.temperature', message: 'Temperature must be between 0 and 2', severity: 'error' });
|
|
275
100
|
}
|
|
276
101
|
|
|
277
102
|
return errors;
|
|
278
103
|
}
|
|
279
104
|
|
|
280
|
-
|
|
281
|
-
* Redis — accepts baseUrl OR url OR host+port.
|
|
282
|
-
* RedisProvider reads opts.baseUrl.
|
|
283
|
-
* Options keys: { baseUrl?: string, url?: string, host?: string, port?: number, apiKey?: string }
|
|
284
|
-
*/
|
|
285
|
-
private static validateRedisConfig(config: VectorDBConfig): ValidationError[] {
|
|
105
|
+
private static async validateEmbeddingConfig(config: EmbeddingConfig): Promise<ValidationError[]> {
|
|
286
106
|
const errors: ValidationError[] = [];
|
|
287
|
-
const opts = config.options as Record<string, unknown>;
|
|
288
|
-
|
|
289
|
-
const hasUrl = Boolean(opts.baseUrl || opts.url);
|
|
290
|
-
const hasHostPort = Boolean(opts.host && opts.port);
|
|
291
107
|
|
|
292
|
-
if (!
|
|
293
|
-
errors.push({
|
|
294
|
-
|
|
295
|
-
message: 'Redis connection is required: provide baseUrl/url or host + port',
|
|
296
|
-
suggestion: 'Set REDIS_URL environment variable',
|
|
297
|
-
severity: 'error',
|
|
298
|
-
});
|
|
108
|
+
if (!config.provider) {
|
|
109
|
+
errors.push({ field: 'embedding.provider', message: 'Embedding provider is required', severity: 'error' });
|
|
110
|
+
return errors;
|
|
299
111
|
}
|
|
300
112
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
* WeaviateProvider reads opts.baseUrl.
|
|
307
|
-
* Options keys: { baseUrl?: string, url?: string, apiKey?: string }
|
|
308
|
-
*/
|
|
309
|
-
private static validateWeaviateConfig(config: VectorDBConfig): ValidationError[] {
|
|
310
|
-
const errors: ValidationError[] = [];
|
|
311
|
-
const opts = config.options as Record<string, unknown>;
|
|
312
|
-
|
|
313
|
-
if (!opts.baseUrl && !opts.url) {
|
|
314
|
-
errors.push({
|
|
315
|
-
field: 'vectorDb.options.baseUrl',
|
|
316
|
-
message: 'Weaviate instance URL is required',
|
|
317
|
-
suggestion: 'Set WEAVIATE_URL environment variable',
|
|
318
|
-
severity: 'error',
|
|
319
|
-
});
|
|
113
|
+
const validator = LLMFactory.getValidator(config.provider as unknown as LLMConfig['provider']);
|
|
114
|
+
if (validator) {
|
|
115
|
+
errors.push(...validator.validate(config as unknown as Record<string, unknown>));
|
|
116
|
+
} else {
|
|
117
|
+
this.fallbackEmbeddingValidation(config, errors);
|
|
320
118
|
}
|
|
321
119
|
|
|
322
120
|
return errors;
|
|
323
121
|
}
|
|
324
122
|
|
|
325
123
|
/**
|
|
326
|
-
*
|
|
327
|
-
* Options key: { baseUrl: string }
|
|
124
|
+
* Temporary fallbacks for providers not yet migrated to the pluggable architecture.
|
|
328
125
|
*/
|
|
329
|
-
private static
|
|
330
|
-
const
|
|
331
|
-
const opts = config.options as Record<string, unknown>;
|
|
332
|
-
|
|
333
|
-
if (!opts.baseUrl) {
|
|
334
|
-
errors.push({
|
|
335
|
-
field: 'vectorDb.options.baseUrl',
|
|
336
|
-
message: 'REST API base URL is required',
|
|
337
|
-
suggestion: 'Set VECTOR_BASE_URL environment variable',
|
|
338
|
-
severity: 'error',
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
return errors;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
private static validateLLMConfig(config: LLMConfig): ValidationError[] {
|
|
346
|
-
const errors: ValidationError[] = [];
|
|
347
|
-
|
|
348
|
-
if (!config.provider) {
|
|
349
|
-
errors.push({
|
|
350
|
-
field: 'llm.provider',
|
|
351
|
-
message: 'LLM provider is required',
|
|
352
|
-
severity: 'error',
|
|
353
|
-
});
|
|
354
|
-
return errors;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (!config.model) {
|
|
358
|
-
errors.push({
|
|
359
|
-
field: 'llm.model',
|
|
360
|
-
message: 'LLM model name is required',
|
|
361
|
-
suggestion: `e.g., "gpt-4o" for OpenAI, "claude-3-opus" for Anthropic`,
|
|
362
|
-
severity: 'error',
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
|
|
126
|
+
private static fallbackVectorValidation(config: VectorDBConfig, errors: ValidationError[]) {
|
|
127
|
+
const opts = (config.options || {}) as Record<string, unknown>;
|
|
366
128
|
switch (config.provider) {
|
|
367
|
-
case '
|
|
368
|
-
if (!
|
|
369
|
-
errors.push({
|
|
370
|
-
field: 'llm.apiKey',
|
|
371
|
-
message: 'OpenAI API key is required',
|
|
372
|
-
suggestion: 'Set OPENAI_API_KEY environment variable',
|
|
373
|
-
severity: 'error',
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
break;
|
|
377
|
-
case 'anthropic':
|
|
378
|
-
if (!config.apiKey) {
|
|
379
|
-
errors.push({
|
|
380
|
-
field: 'llm.apiKey',
|
|
381
|
-
message: 'Anthropic API key is required',
|
|
382
|
-
suggestion: 'Set ANTHROPIC_API_KEY environment variable',
|
|
383
|
-
severity: 'error',
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
break;
|
|
387
|
-
case 'gemini':
|
|
388
|
-
if (!config.apiKey) {
|
|
389
|
-
errors.push({
|
|
390
|
-
field: 'llm.apiKey',
|
|
391
|
-
message: 'Gemini API key is required',
|
|
392
|
-
suggestion: 'Set GEMINI_API_KEY environment variable',
|
|
393
|
-
severity: 'error',
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
break;
|
|
397
|
-
case 'ollama':
|
|
398
|
-
if (!config.baseUrl) {
|
|
399
|
-
errors.push({
|
|
400
|
-
field: 'llm.baseUrl',
|
|
401
|
-
message: 'Ollama base URL is required',
|
|
402
|
-
suggestion: 'Set LLM_BASE_URL environment variable (e.g., "http://localhost:11434")',
|
|
403
|
-
severity: 'error',
|
|
404
|
-
});
|
|
129
|
+
case 'milvus':
|
|
130
|
+
if (!opts.baseUrl && !opts.uri && !(opts.host && opts.port)) {
|
|
131
|
+
errors.push({ field: 'vectorDb.options.baseUrl', message: 'Milvus connection info required', severity: 'error' });
|
|
405
132
|
}
|
|
406
133
|
break;
|
|
407
|
-
case '
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
errors.push({
|
|
411
|
-
field: 'llm.baseUrl',
|
|
412
|
-
message: 'REST API base URL is required',
|
|
413
|
-
suggestion: 'Set LLM_BASE_URL environment variable',
|
|
414
|
-
severity: 'error',
|
|
415
|
-
});
|
|
134
|
+
case 'qdrant':
|
|
135
|
+
if (!opts.baseUrl && !opts.url) {
|
|
136
|
+
errors.push({ field: 'vectorDb.options.baseUrl', message: 'Qdrant URL required', severity: 'error' });
|
|
416
137
|
}
|
|
417
138
|
break;
|
|
139
|
+
// ... other fallbacks
|
|
418
140
|
}
|
|
419
|
-
|
|
420
|
-
if (config.temperature !== undefined) {
|
|
421
|
-
if (config.temperature < 0 || config.temperature > 2) {
|
|
422
|
-
errors.push({
|
|
423
|
-
field: 'llm.temperature',
|
|
424
|
-
message: 'Temperature must be between 0 and 2',
|
|
425
|
-
severity: 'error',
|
|
426
|
-
});
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
if (config.maxTokens !== undefined && config.maxTokens <= 0) {
|
|
431
|
-
errors.push({
|
|
432
|
-
field: 'llm.maxTokens',
|
|
433
|
-
message: 'maxTokens must be greater than 0',
|
|
434
|
-
severity: 'error',
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return errors;
|
|
439
141
|
}
|
|
440
142
|
|
|
441
|
-
private static
|
|
442
|
-
const errors: ValidationError[] = [];
|
|
443
|
-
|
|
444
|
-
if (!config.provider) {
|
|
445
|
-
errors.push({
|
|
446
|
-
field: 'embedding.provider',
|
|
447
|
-
message: 'Embedding provider is required',
|
|
448
|
-
severity: 'error',
|
|
449
|
-
});
|
|
450
|
-
return errors;
|
|
451
|
-
}
|
|
452
|
-
|
|
143
|
+
private static fallbackLLMValidation(config: LLMConfig, errors: ValidationError[]) {
|
|
453
144
|
if (!config.model) {
|
|
454
|
-
errors.push({
|
|
455
|
-
field: 'embedding.model',
|
|
456
|
-
message: 'Embedding model name is required',
|
|
457
|
-
suggestion: 'e.g., "text-embedding-3-small" for OpenAI, "nomic-embed-text" for Ollama',
|
|
458
|
-
severity: 'error',
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
if (config.provider === 'openai' && !config.apiKey) {
|
|
463
|
-
errors.push({
|
|
464
|
-
field: 'embedding.apiKey',
|
|
465
|
-
message: 'OpenAI API key is required for embedding',
|
|
466
|
-
suggestion: 'Set OPENAI_API_KEY environment variable',
|
|
467
|
-
severity: 'error',
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
if (config.provider === 'gemini' && !config.apiKey) {
|
|
472
|
-
errors.push({
|
|
473
|
-
field: 'embedding.apiKey',
|
|
474
|
-
message: 'Gemini API key is required for embedding',
|
|
475
|
-
suggestion: 'Set GEMINI_API_KEY environment variable',
|
|
476
|
-
severity: 'error',
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
if (config.provider === 'ollama' && !config.baseUrl) {
|
|
481
|
-
errors.push({
|
|
482
|
-
field: 'embedding.baseUrl',
|
|
483
|
-
message: 'Ollama base URL is required for embedding',
|
|
484
|
-
suggestion: 'Set EMBEDDING_BASE_URL environment variable',
|
|
485
|
-
severity: 'error',
|
|
486
|
-
});
|
|
145
|
+
errors.push({ field: 'llm.model', message: 'LLM model name is required', severity: 'error' });
|
|
487
146
|
}
|
|
147
|
+
// Add other LLM fallbacks if needed
|
|
148
|
+
}
|
|
488
149
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
message: 'Embedding dimensions must be greater than 0',
|
|
493
|
-
severity: 'error',
|
|
494
|
-
});
|
|
150
|
+
private static fallbackEmbeddingValidation(config: EmbeddingConfig, errors: ValidationError[]) {
|
|
151
|
+
if (!config.model) {
|
|
152
|
+
errors.push({ field: 'embedding.model', message: 'Embedding model name is required', severity: 'error' });
|
|
495
153
|
}
|
|
496
|
-
|
|
497
|
-
return errors;
|
|
498
154
|
}
|
|
499
155
|
|
|
500
156
|
private static validateUIConfig(config: Record<string, unknown>): ValidationError[] {
|
|
501
157
|
const errors: ValidationError[] = [];
|
|
502
158
|
|
|
503
|
-
if (config.primaryColor) {
|
|
504
|
-
|
|
505
|
-
errors.push({
|
|
506
|
-
field: 'ui.primaryColor',
|
|
507
|
-
message: 'Invalid CSS color format',
|
|
508
|
-
suggestion: 'Use valid CSS colors: hex (#FF0000), rgb, hsl, or named colors',
|
|
509
|
-
severity: 'warning',
|
|
510
|
-
});
|
|
511
|
-
}
|
|
159
|
+
if (config.primaryColor && !this.isValidCSSColor(config.primaryColor as string)) {
|
|
160
|
+
errors.push({ field: 'ui.primaryColor', message: 'Invalid CSS color format', severity: 'warning' });
|
|
512
161
|
}
|
|
513
162
|
|
|
514
|
-
if (config.borderRadius) {
|
|
515
|
-
|
|
516
|
-
errors.push({
|
|
517
|
-
field: 'ui.borderRadius',
|
|
518
|
-
message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(', ')}`,
|
|
519
|
-
severity: 'warning',
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
if (config.visualStyle) {
|
|
525
|
-
if (!UI_VISUAL_STYLES.includes(config.visualStyle as (typeof UI_VISUAL_STYLES)[number])) {
|
|
526
|
-
errors.push({
|
|
527
|
-
field: 'ui.visualStyle',
|
|
528
|
-
message: `visualStyle must be one of: ${UI_VISUAL_STYLES.join(', ')}`,
|
|
529
|
-
severity: 'warning',
|
|
530
|
-
});
|
|
531
|
-
}
|
|
163
|
+
if (config.borderRadius && !UI_BORDER_RADIUS_OPTIONS.includes(config.borderRadius as typeof UI_BORDER_RADIUS_OPTIONS[number])) {
|
|
164
|
+
errors.push({ field: 'ui.borderRadius', message: `borderRadius must be one of: ${UI_BORDER_RADIUS_OPTIONS.join(', ')}`, severity: 'warning' });
|
|
532
165
|
}
|
|
533
166
|
|
|
534
167
|
return errors;
|
|
@@ -536,81 +169,22 @@ export class ConfigValidator {
|
|
|
536
169
|
|
|
537
170
|
private static validateRAGConfig(config: Record<string, unknown>): ValidationError[] {
|
|
538
171
|
const errors: ValidationError[] = [];
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
if (typeof config.topK !== 'number' || config.topK <= 0) {
|
|
542
|
-
errors.push({
|
|
543
|
-
field: 'rag.topK',
|
|
544
|
-
message: 'topK must be a positive integer',
|
|
545
|
-
severity: 'error',
|
|
546
|
-
});
|
|
547
|
-
}
|
|
172
|
+
if (config.topK !== undefined && (typeof config.topK !== 'number' || config.topK <= 0)) {
|
|
173
|
+
errors.push({ field: 'rag.topK', message: 'topK must be a positive integer', severity: 'error' });
|
|
548
174
|
}
|
|
549
|
-
|
|
550
|
-
if (config.scoreThreshold !== undefined) {
|
|
551
|
-
if (typeof config.scoreThreshold !== 'number' || config.scoreThreshold < 0 || config.scoreThreshold > 1) {
|
|
552
|
-
errors.push({
|
|
553
|
-
field: 'rag.scoreThreshold',
|
|
554
|
-
message: 'scoreThreshold must be between 0 and 1',
|
|
555
|
-
severity: 'error',
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
if (config.chunkSize !== undefined) {
|
|
561
|
-
if (typeof config.chunkSize !== 'number' || config.chunkSize <= 0) {
|
|
562
|
-
errors.push({
|
|
563
|
-
field: 'rag.chunkSize',
|
|
564
|
-
message: 'chunkSize must be a positive integer',
|
|
565
|
-
severity: 'error',
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
if (config.chunkOverlap !== undefined) {
|
|
571
|
-
if (typeof config.chunkOverlap !== 'number' || config.chunkOverlap < 0) {
|
|
572
|
-
errors.push({
|
|
573
|
-
field: 'rag.chunkOverlap',
|
|
574
|
-
message: 'chunkOverlap must be a non-negative integer',
|
|
575
|
-
severity: 'error',
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
175
|
return errors;
|
|
581
176
|
}
|
|
582
177
|
|
|
583
178
|
private static isValidCSSColor(color: string): boolean {
|
|
584
179
|
const hexRegex = /^#([0-9a-f]{3}){1,2}$/i;
|
|
585
180
|
const rgbRegex = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/i;
|
|
586
|
-
const hslRegex = /^hsla?\((\d+),\s*(\d+)%,\s*(\d+)%(?:,\s*(\d+(?:\.\d+)?))?\)$/i;
|
|
587
181
|
const namedColors = ['red', 'blue', 'green', 'black', 'white', 'transparent'];
|
|
588
|
-
|
|
589
|
-
return (
|
|
590
|
-
hexRegex.test(color) ||
|
|
591
|
-
rgbRegex.test(color) ||
|
|
592
|
-
hslRegex.test(color) ||
|
|
593
|
-
namedColors.includes(color.toLowerCase())
|
|
594
|
-
);
|
|
182
|
+
return hexRegex.test(color) || rgbRegex.test(color) || namedColors.includes(color.toLowerCase());
|
|
595
183
|
}
|
|
596
184
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
* Logs warnings to console.
|
|
600
|
-
*/
|
|
601
|
-
static validateAndThrow(config: RagConfig): void {
|
|
602
|
-
const errors = this.validate(config);
|
|
603
|
-
|
|
185
|
+
static async validateAndThrow(config: RagConfig): Promise<void> {
|
|
186
|
+
const errors = await this.validate(config);
|
|
604
187
|
const errorItems = errors.filter((e) => e.severity === 'error');
|
|
605
|
-
const warnings = errors.filter((e) => e.severity === 'warning');
|
|
606
|
-
|
|
607
|
-
if (warnings.length > 0) {
|
|
608
|
-
console.warn('[ConfigValidator] Configuration warnings:');
|
|
609
|
-
warnings.forEach((w) => {
|
|
610
|
-
console.warn(` ${w.field}: ${w.message}`);
|
|
611
|
-
if (w.suggestion) console.warn(` Suggestion: ${w.suggestion}`);
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
188
|
|
|
615
189
|
if (errorItems.length > 0) {
|
|
616
190
|
const message = errorItems
|