@retrivora-ai/rag-engine 0.1.6 → 0.1.8

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 (51) hide show
  1. package/dist/{ChromaDBProvider-QNI7UCX4.mjs → ChromaDBProvider-2JZSBOQX.mjs} +1 -1
  2. package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-CJDBCBVI.mjs} +1 -1
  3. package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-E6L5Z2FO.mjs} +1 -1
  4. package/dist/{QdrantProvider-NYGHAA7C.mjs → QdrantProvider-JITRNJQN.mjs} +1 -1
  5. package/dist/{RagConfig-hBGXJmSx.d.mts → RagConfig-D_rSf8ep.d.mts} +1 -1
  6. package/dist/{RagConfig-hBGXJmSx.d.ts → RagConfig-D_rSf8ep.d.ts} +1 -1
  7. package/dist/{RedisProvider-ASONNYBI.mjs → RedisProvider-3VKFQXXD.mjs} +1 -1
  8. package/dist/UniversalVectorProvider-E6L4U4OX.mjs +9 -0
  9. package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-MXIPP44J.mjs} +1 -1
  10. package/dist/{chunk-5K23H7JL.mjs → chunk-26EMHLIN.mjs} +40 -2
  11. package/dist/{chunk-VPNRDXIA.mjs → chunk-7BQI4A5J.mjs} +17 -11
  12. package/dist/{chunk-ZM6TYIDH.mjs → chunk-MFWJZVF3.mjs} +3 -1
  13. package/dist/{chunk-V75V7BT2.mjs → chunk-TSX6DQXX.mjs} +2 -2
  14. package/dist/{chunk-HUGLYKD6.mjs → chunk-XZPVJS2B.mjs} +27 -9
  15. package/dist/chunk-Y6HQZDCJ.mjs +156 -0
  16. package/dist/{chunk-HSBXE2WV.mjs → chunk-YIYDJQJM.mjs} +745 -192
  17. package/dist/{chunk-7NXI6ZWX.mjs → chunk-YST6KYBJ.mjs} +8 -5
  18. package/dist/handlers/index.d.mts +2 -2
  19. package/dist/handlers/index.d.ts +2 -2
  20. package/dist/handlers/index.js +924 -626
  21. package/dist/handlers/index.mjs +1 -2
  22. package/dist/index-BJ8CUArE.d.mts +114 -0
  23. package/dist/index-DtNprGGj.d.ts +114 -0
  24. package/dist/index.d.mts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/server.d.mts +575 -17
  27. package/dist/server.d.ts +575 -17
  28. package/dist/server.js +1280 -643
  29. package/dist/server.mjs +314 -16
  30. package/package.json +11 -2
  31. package/src/config/ConfigBuilder.ts +373 -0
  32. package/src/config/EmbeddingStrategy.ts +147 -0
  33. package/src/config/serverConfig.ts +51 -17
  34. package/src/core/ConfigValidator.ts +77 -52
  35. package/src/core/Pipeline.ts +28 -26
  36. package/src/core/PluginManager.ts +277 -0
  37. package/src/core/ProviderHealthCheck.ts +79 -140
  38. package/src/core/ProviderRegistry.ts +38 -15
  39. package/src/providers/vectordb/ChromaDBProvider.ts +37 -12
  40. package/src/providers/vectordb/MilvusProvider.ts +25 -10
  41. package/src/providers/vectordb/PineconeProvider.ts +17 -2
  42. package/src/providers/vectordb/QdrantProvider.ts +46 -2
  43. package/src/providers/vectordb/RedisProvider.ts +34 -11
  44. package/src/providers/vectordb/UniversalVectorProvider.ts +220 -0
  45. package/src/providers/vectordb/WeaviateProvider.ts +17 -10
  46. package/src/server.ts +28 -10
  47. package/dist/LLMFactory-JFOY2V4X.mjs +0 -8
  48. package/dist/chunk-JI6VD5TJ.mjs +0 -387
  49. package/dist/index-Bx182KKn.d.ts +0 -64
  50. package/dist/index-Ck2pt7-8.d.mts +0 -64
  51. package/src/test-refactor.ts +0 -59
package/dist/server.js CHANGED
@@ -92,422 +92,6 @@ var init_templateUtils = __esm({
92
92
  }
93
93
  });
94
94
 
95
- // src/llm/providers/OpenAIProvider.ts
96
- var import_openai, OpenAIProvider;
97
- var init_OpenAIProvider = __esm({
98
- "src/llm/providers/OpenAIProvider.ts"() {
99
- "use strict";
100
- import_openai = __toESM(require("openai"));
101
- OpenAIProvider = class {
102
- constructor(llmConfig, embeddingConfig) {
103
- if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
104
- this.client = new import_openai.default({ apiKey: llmConfig.apiKey });
105
- this.llmConfig = llmConfig;
106
- this.embeddingConfig = embeddingConfig;
107
- }
108
- async chat(messages, context, options) {
109
- var _a, _b, _c, _d, _e, _f, _g, _h;
110
- const systemContent = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
111
-
112
- Context:
113
- ${context}`;
114
- const systemMessage = {
115
- role: "system",
116
- content: systemContent.includes("{{context}}") ? systemContent.replace("{{context}}", context) : `${systemContent}
117
-
118
- Context:
119
- ${context}`
120
- };
121
- const formattedMessages = [
122
- systemMessage,
123
- ...messages.map((m) => ({
124
- role: m.role,
125
- content: m.content
126
- }))
127
- ];
128
- const completion = await this.client.chat.completions.create({
129
- model: this.llmConfig.model,
130
- messages: formattedMessages,
131
- max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
132
- temperature: (_e = (_d = options == null ? void 0 : options.temperature) != null ? _d : this.llmConfig.temperature) != null ? _e : 0.7,
133
- stop: options == null ? void 0 : options.stop
134
- });
135
- return (_h = (_g = (_f = completion.choices[0]) == null ? void 0 : _f.message) == null ? void 0 : _g.content) != null ? _h : "";
136
- }
137
- async embed(text, options) {
138
- const results = await this.batchEmbed([text], options);
139
- return results[0];
140
- }
141
- async batchEmbed(texts, options) {
142
- var _a, _b, _c, _d, _e;
143
- const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-3-small";
144
- const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
145
- const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
146
- const response = await client.embeddings.create({ model, input: texts });
147
- return response.data.map((d) => d.embedding);
148
- }
149
- async ping() {
150
- try {
151
- await this.client.models.list();
152
- return true;
153
- } catch (err) {
154
- console.error("[OpenAIProvider] Ping failed:", err);
155
- return false;
156
- }
157
- }
158
- };
159
- }
160
- });
161
-
162
- // src/llm/providers/AnthropicProvider.ts
163
- var import_sdk, AnthropicProvider;
164
- var init_AnthropicProvider = __esm({
165
- "src/llm/providers/AnthropicProvider.ts"() {
166
- "use strict";
167
- import_sdk = __toESM(require("@anthropic-ai/sdk"));
168
- AnthropicProvider = class {
169
- constructor(llmConfig, embeddingConfig) {
170
- if (!llmConfig.apiKey) throw new Error("[AnthropicProvider] llmConfig.apiKey is required");
171
- this.client = new import_sdk.default({ apiKey: llmConfig.apiKey });
172
- this.llmConfig = llmConfig;
173
- this.embeddingConfig = embeddingConfig;
174
- }
175
- async chat(messages, context, options) {
176
- var _a, _b, _c;
177
- const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the context below to answer the user's question accurately.
178
-
179
- Context:
180
- ${context}`;
181
- const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
182
-
183
- Context:
184
- ${context}`;
185
- const anthropicMessages = messages.map((m) => ({
186
- role: m.role === "assistant" ? "assistant" : "user",
187
- content: m.content
188
- }));
189
- const response = await this.client.messages.create({
190
- model: this.llmConfig.model,
191
- max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
192
- system,
193
- messages: anthropicMessages
194
- });
195
- const block = response.content[0];
196
- return block.type === "text" ? block.text : "";
197
- }
198
- /**
199
- * Anthropic does not offer an embedding API.
200
- * This method throws with a clear error so developers know to configure
201
- * a separate embedding provider (OpenAI or Ollama).
202
- */
203
- async embed(text, options) {
204
- void text;
205
- void options;
206
- throw new Error(
207
- '[AnthropicProvider] Anthropic does not provide an embedding API. Set embedding.provider to "openai" or "ollama" in your RagConfig.'
208
- );
209
- }
210
- async batchEmbed(texts, options) {
211
- void texts;
212
- void options;
213
- throw new Error(
214
- "[AnthropicProvider] Anthropic does not provide an embedding API."
215
- );
216
- }
217
- async ping() {
218
- try {
219
- await this.client.models.list();
220
- return true;
221
- } catch (err) {
222
- console.error("[AnthropicProvider] Ping failed:", err);
223
- return false;
224
- }
225
- }
226
- };
227
- }
228
- });
229
-
230
- // src/llm/providers/OllamaProvider.ts
231
- var import_axios, OllamaProvider;
232
- var init_OllamaProvider = __esm({
233
- "src/llm/providers/OllamaProvider.ts"() {
234
- "use strict";
235
- import_axios = __toESM(require("axios"));
236
- OllamaProvider = class {
237
- constructor(llmConfig, embeddingConfig) {
238
- var _a;
239
- const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
240
- this.http = import_axios.default.create({ baseURL, timeout: 12e4 });
241
- this.llmConfig = llmConfig;
242
- this.embeddingConfig = embeddingConfig;
243
- }
244
- async chat(messages, context, options) {
245
- var _a, _b, _c, _d, _e;
246
- const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
247
-
248
- Context:
249
- ${context}`;
250
- const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
251
-
252
- Context:
253
- ${context}`;
254
- const { data } = await this.http.post("/api/chat", {
255
- model: this.llmConfig.model,
256
- stream: false,
257
- options: {
258
- temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
259
- num_predict: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024
260
- },
261
- messages: [
262
- { role: "system", content: system },
263
- ...messages.map((m) => ({ role: m.role, content: m.content }))
264
- ]
265
- });
266
- return data.message.content;
267
- }
268
- async embed(text, options) {
269
- var _a, _b, _c, _d, _e, _f, _g;
270
- const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
271
- const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
272
- const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
273
- const { data } = await client.post("/api/embeddings", {
274
- model,
275
- prompt: text
276
- });
277
- return data.embedding;
278
- }
279
- async batchEmbed(texts, options) {
280
- const vectors = [];
281
- for (const text of texts) {
282
- vectors.push(await this.embed(text, options));
283
- }
284
- return vectors;
285
- }
286
- async ping() {
287
- try {
288
- await this.http.get("/api/tags");
289
- return true;
290
- } catch (err) {
291
- console.error("[OllamaProvider] Ping failed:", err);
292
- return false;
293
- }
294
- }
295
- };
296
- }
297
- });
298
-
299
- // src/config/UniversalProfiles.ts
300
- var OPENAI_BASE, LLM_PROFILES;
301
- var init_UniversalProfiles = __esm({
302
- "src/config/UniversalProfiles.ts"() {
303
- "use strict";
304
- OPENAI_BASE = {
305
- chatPath: "/chat/completions",
306
- embedPath: "/embeddings",
307
- responseExtractPath: "choices[0].message.content",
308
- embedExtractPath: "data[0].embedding",
309
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
310
- };
311
- LLM_PROFILES = {
312
- "openai-compatible": OPENAI_BASE,
313
- "litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
314
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
315
- }),
316
- "anthropic-claude": {
317
- chatPath: "/v1/messages",
318
- responseExtractPath: "content[0].text",
319
- headers: { "anthropic-version": "2023-06-01" },
320
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
321
- },
322
- "google-gemini": {
323
- chatPath: "/v1beta/models/{{model}}:generateContent",
324
- responseExtractPath: "candidates[0].content.parts[0].text",
325
- chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
326
- },
327
- "github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
328
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
329
- }),
330
- "ollama-standard": {
331
- chatPath: "/api/chat",
332
- embedPath: "/api/embeddings",
333
- responseExtractPath: "message.content",
334
- embedExtractPath: "embedding",
335
- chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
336
- embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
337
- }
338
- };
339
- }
340
- });
341
-
342
- // src/llm/providers/UniversalLLMAdapter.ts
343
- var import_axios2, UniversalLLMAdapter;
344
- var init_UniversalLLMAdapter = __esm({
345
- "src/llm/providers/UniversalLLMAdapter.ts"() {
346
- "use strict";
347
- import_axios2 = __toESM(require("axios"));
348
- init_templateUtils();
349
- init_UniversalProfiles();
350
- UniversalLLMAdapter = class {
351
- constructor(config) {
352
- var _a, _b, _c, _d, _e, _f, _g;
353
- this.model = config.model;
354
- const llmConfig = config;
355
- const options = (_a = llmConfig.options) != null ? _a : {};
356
- let profile = {};
357
- if (typeof options.profile === "string") {
358
- profile = LLM_PROFILES[options.profile] || {};
359
- } else if (typeof options.profile === "object" && options.profile !== null) {
360
- profile = options.profile;
361
- }
362
- this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
363
- this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
364
- this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
365
- this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
366
- const baseUrl = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl;
367
- if (!baseUrl) {
368
- throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
369
- }
370
- this.http = import_axios2.default.create({
371
- baseURL: baseUrl,
372
- headers: __spreadValues(__spreadValues({
373
- "Content-Type": "application/json"
374
- }, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {}),
375
- timeout: (_g = this.opts.timeout) != null ? _g : 6e4
376
- });
377
- }
378
- async chat(messages, context) {
379
- var _a, _b;
380
- const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
381
- const formattedMessages = [
382
- { role: "system", content: `${this.systemPrompt}
383
-
384
- Context:
385
- ${context != null ? context : "None"}` },
386
- ...messages
387
- ];
388
- let payload;
389
- if (this.opts.chatPayloadTemplate) {
390
- payload = buildPayload(this.opts.chatPayloadTemplate, {
391
- model: this.model,
392
- messages: formattedMessages,
393
- maxTokens: this.maxTokens,
394
- temperature: this.temperature
395
- });
396
- } else {
397
- payload = {
398
- model: this.model,
399
- messages: formattedMessages,
400
- max_tokens: this.maxTokens,
401
- temperature: this.temperature
402
- };
403
- }
404
- const { data } = await this.http.post(path, payload);
405
- const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
406
- const result = resolvePath(data, extractPath);
407
- if (result === void 0) {
408
- throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
409
- }
410
- return String(result);
411
- }
412
- async embed(text) {
413
- var _a, _b;
414
- const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
415
- let payload;
416
- if (this.opts.embedPayloadTemplate) {
417
- payload = buildPayload(this.opts.embedPayloadTemplate, {
418
- model: this.model,
419
- input: text
420
- });
421
- } else {
422
- payload = {
423
- model: this.model,
424
- input: text
425
- };
426
- }
427
- const { data } = await this.http.post(path, payload);
428
- const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
429
- const vector = resolvePath(data, extractPath);
430
- if (!Array.isArray(vector)) {
431
- throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
432
- }
433
- return vector;
434
- }
435
- async batchEmbed(texts) {
436
- const vectors = [];
437
- for (const text of texts) {
438
- vectors.push(await this.embed(text));
439
- }
440
- return vectors;
441
- }
442
- async ping() {
443
- try {
444
- if (this.opts.pingPath) {
445
- await this.http.get(this.opts.pingPath);
446
- }
447
- return true;
448
- } catch (err) {
449
- console.error("[UniversalLLMAdapter] Ping failed:", err);
450
- return false;
451
- }
452
- }
453
- };
454
- }
455
- });
456
-
457
- // src/llm/LLMFactory.ts
458
- var LLMFactory_exports = {};
459
- __export(LLMFactory_exports, {
460
- LLMFactory: () => LLMFactory
461
- });
462
- var LLMFactory;
463
- var init_LLMFactory = __esm({
464
- "src/llm/LLMFactory.ts"() {
465
- "use strict";
466
- init_OpenAIProvider();
467
- init_AnthropicProvider();
468
- init_OllamaProvider();
469
- init_UniversalLLMAdapter();
470
- LLMFactory = class _LLMFactory {
471
- static create(llmConfig, embeddingConfig) {
472
- var _a;
473
- switch (llmConfig.provider) {
474
- case "openai":
475
- return new OpenAIProvider(llmConfig, embeddingConfig);
476
- case "anthropic":
477
- return new AnthropicProvider(llmConfig, embeddingConfig);
478
- case "ollama":
479
- return new OllamaProvider(llmConfig, embeddingConfig);
480
- case "rest":
481
- case "universal_rest":
482
- case "custom":
483
- return new UniversalLLMAdapter(llmConfig);
484
- default:
485
- if (llmConfig.baseUrl || ((_a = llmConfig.options) == null ? void 0 : _a.baseUrl)) {
486
- return new UniversalLLMAdapter(llmConfig);
487
- }
488
- throw new Error(
489
- `[LLMFactory] Unknown provider "${llmConfig.provider}". Supported: openai | anthropic | ollama | rest | custom`
490
- );
491
- }
492
- }
493
- /**
494
- * Creates a dedicated embedding-only provider.
495
- * Useful when the LLM provider (e.g. Anthropic) doesn't support embeddings.
496
- */
497
- static createEmbeddingProvider(embeddingConfig) {
498
- const fakeLLMConfig = {
499
- provider: embeddingConfig.provider,
500
- model: embeddingConfig.model,
501
- apiKey: embeddingConfig.apiKey,
502
- baseUrl: embeddingConfig.baseUrl,
503
- options: embeddingConfig.options
504
- };
505
- return _LLMFactory.create(fakeLLMConfig, embeddingConfig);
506
- }
507
- };
508
- }
509
- });
510
-
511
95
  // src/providers/vectordb/BaseVectorProvider.ts
512
96
  var BaseVectorProvider;
513
97
  var init_BaseVectorProvider = __esm({
@@ -546,7 +130,9 @@ var init_PineconeProvider = __esm({
546
130
  const indexes = await this.client.listIndexes();
547
131
  const names = (_b = (_a = indexes.indexes) == null ? void 0 : _a.map((i) => i.name)) != null ? _b : [];
548
132
  if (!names.includes(this.indexName)) {
549
- throw new Error(`[PineconeProvider] Index "${this.indexName}" not found.`);
133
+ throw new Error(
134
+ `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
135
+ );
550
136
  }
551
137
  }
552
138
  index(namespace) {
@@ -875,8 +461,8 @@ var init_MilvusProvider = __esm({
875
461
  constructor(config) {
876
462
  super(config);
877
463
  const opts = config.options;
878
- const baseUrl = opts.baseUrl || opts.uri;
879
- if (!baseUrl) throw new Error("[MilvusProvider] baseUrl/uri is required");
464
+ const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : void 0);
465
+ if (!baseUrl) throw new Error("[MilvusProvider] options.baseUrl (or uri / host+port) is required");
880
466
  this.http = import_axios3.default.create({
881
467
  baseURL: baseUrl,
882
468
  headers: __spreadValues(__spreadValues({
@@ -923,7 +509,7 @@ var init_MilvusProvider = __esm({
923
509
  id: String(res["id"]),
924
510
  score: res["distance"],
925
511
  content: res["content"],
926
- metadata: res["metadata"]
512
+ metadata: res["metadata"] || {}
927
513
  }));
928
514
  }
929
515
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -933,8 +519,11 @@ var init_MilvusProvider = __esm({
933
519
  id
934
520
  });
935
521
  }
936
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
937
- async deleteNamespace(_namespace) {
522
+ async deleteNamespace(namespace) {
523
+ await this.http.post("/v1/vector/delete", {
524
+ collectionName: this.indexName,
525
+ filter: `namespace == "${namespace}"`
526
+ });
938
527
  }
939
528
  async ping() {
940
529
  try {
@@ -955,11 +544,12 @@ var QdrantProvider_exports = {};
955
544
  __export(QdrantProvider_exports, {
956
545
  QdrantProvider: () => QdrantProvider
957
546
  });
958
- var import_axios4, QdrantProvider;
547
+ var import_axios4, import_crypto, QdrantProvider;
959
548
  var init_QdrantProvider = __esm({
960
549
  "src/providers/vectordb/QdrantProvider.ts"() {
961
550
  "use strict";
962
551
  import_axios4 = __toESM(require("axios"));
552
+ import_crypto = __toESM(require("crypto"));
963
553
  init_BaseVectorProvider();
964
554
  QdrantProvider = class extends BaseVectorProvider {
965
555
  constructor(config) {
@@ -976,8 +566,34 @@ var init_QdrantProvider = __esm({
976
566
  }
977
567
  async initialize() {
978
568
  await this.ping();
569
+ await this.ensureCollection();
979
570
  await this.ensureIndex();
980
571
  }
572
+ /**
573
+ * Ensures the collection exists. Creates it if missing.
574
+ */
575
+ async ensureCollection() {
576
+ var _a;
577
+ try {
578
+ await this.http.get(`/collections/${this.indexName}`);
579
+ console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
580
+ } catch (err) {
581
+ if (import_axios4.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
582
+ const opts = this.config.options;
583
+ const dimensionsForCreate = opts.dimensions || 1536;
584
+ console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
585
+ await this.http.put(`/collections/${this.indexName}`, {
586
+ vectors: {
587
+ size: dimensionsForCreate,
588
+ distance: "Cosine"
589
+ }
590
+ });
591
+ console.log(`[QdrantProvider] \u2705 Created collection "${this.indexName}"`);
592
+ } else {
593
+ throw err;
594
+ }
595
+ }
596
+ }
981
597
  /**
982
598
  * Ensures that the 'namespace' field has a keyword index for efficient filtering.
983
599
  * Qdrant requires this for search filters to work in many configurations.
@@ -1010,7 +626,7 @@ var init_QdrantProvider = __esm({
1010
626
  async batchUpsert(docs, namespace) {
1011
627
  const payload = {
1012
628
  points: docs.map((doc) => ({
1013
- id: doc.id,
629
+ id: this.normalizeId(doc.id),
1014
630
  vector: doc.vector,
1015
631
  payload: __spreadValues({
1016
632
  content: doc.content,
@@ -1044,7 +660,7 @@ var init_QdrantProvider = __esm({
1044
660
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1045
661
  async delete(id, _namespace) {
1046
662
  await this.http.post(`/collections/${this.indexName}/points/delete`, {
1047
- points: [id]
663
+ points: [this.normalizeId(id)]
1048
664
  });
1049
665
  }
1050
666
  async deleteNamespace(_namespace) {
@@ -1062,6 +678,17 @@ var init_QdrantProvider = __esm({
1062
678
  return false;
1063
679
  }
1064
680
  }
681
+ /**
682
+ * Normalizes an ID into a format Qdrant accepts (UUID or integer).
683
+ * For string IDs that aren't UUIDs, it generates a deterministic UUID v5-like hash.
684
+ */
685
+ normalizeId(id) {
686
+ if (typeof id === "number") return id;
687
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
688
+ if (uuidRegex.test(id)) return id.toLowerCase();
689
+ const hash = import_crypto.default.createHash("md5").update(id).digest("hex");
690
+ return `${hash.slice(0, 8)}-${hash.slice(8, 12)}-${hash.slice(12, 16)}-${hash.slice(16, 20)}-${hash.slice(20, 32)}`;
691
+ }
1065
692
  async disconnect() {
1066
693
  }
1067
694
  };
@@ -1084,23 +711,41 @@ var init_ChromaDBProvider = __esm({
1084
711
  super(config);
1085
712
  this.collectionId = "";
1086
713
  const opts = config.options;
1087
- const baseUrl = opts.baseUrl;
1088
- if (!baseUrl) throw new Error("[ChromaDBProvider] baseUrl is required");
714
+ const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : void 0);
715
+ if (!baseUrl) throw new Error("[ChromaDBProvider] options.baseUrl is required");
1089
716
  this.http = import_axios5.default.create({
1090
717
  baseURL: baseUrl,
1091
718
  headers: { "Content-Type": "application/json" }
1092
719
  });
1093
720
  }
721
+ /**
722
+ * Get or create the ChromaDB collection.
723
+ */
1094
724
  async initialize() {
1095
- const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
1096
- this.collectionId = data.id;
725
+ var _a;
726
+ try {
727
+ const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
728
+ this.collectionId = data.id;
729
+ console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
730
+ } catch (err) {
731
+ if (import_axios5.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
732
+ console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
733
+ const { data } = await this.http.post("/api/v1/collections", {
734
+ name: this.indexName
735
+ });
736
+ this.collectionId = data.id;
737
+ console.log(`[ChromaDBProvider] \u2705 Created collection "${this.indexName}" (id: ${this.collectionId})`);
738
+ } else {
739
+ throw err;
740
+ }
741
+ }
1097
742
  }
1098
743
  async upsert(doc, namespace) {
1099
744
  await this.batchUpsert([doc], namespace);
1100
745
  }
1101
746
  async batchUpsert(docs, namespace) {
1102
747
  const payload = {
1103
- ids: docs.map((d) => d.id),
748
+ ids: docs.map((d) => String(d.id)),
1104
749
  embeddings: docs.map((d) => d.vector),
1105
750
  documents: docs.map((d) => d.content),
1106
751
  metadatas: docs.map((d) => __spreadValues(__spreadValues({}, d.metadata || {}), namespace ? { namespace } : {}))
@@ -1128,15 +773,15 @@ var init_ChromaDBProvider = __esm({
1128
773
  }
1129
774
  return matches;
1130
775
  }
1131
- async delete(id, _namespace) {
776
+ async delete(id, namespace) {
1132
777
  await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
1133
778
  ids: [id],
1134
- where: _namespace ? { namespace: { $eq: _namespace } } : void 0
779
+ where: namespace ? { namespace: { $eq: namespace } } : void 0
1135
780
  });
1136
781
  }
1137
- async deleteNamespace(_namespace) {
782
+ async deleteNamespace(namespace) {
1138
783
  await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
1139
- where: { namespace: { $eq: _namespace } }
784
+ where: { namespace: { $eq: namespace } }
1140
785
  });
1141
786
  }
1142
787
  async ping() {
@@ -1168,21 +813,20 @@ var init_RedisProvider = __esm({
1168
813
  constructor(config) {
1169
814
  super(config);
1170
815
  const opts = config.options;
1171
- const baseUrl = opts.baseUrl;
1172
- if (!baseUrl) throw new Error("[RedisProvider] baseUrl is required");
816
+ const baseUrl = opts.baseUrl || opts.url || (opts.host ? `http://${opts.host}:${opts.port || 6379}` : void 0);
817
+ if (!baseUrl) throw new Error("[RedisProvider] options.baseUrl is required");
1173
818
  this.http = import_axios6.default.create({
1174
819
  baseURL: baseUrl,
1175
- headers: {
1176
- "Content-Type": "application/json",
1177
- Authorization: `Bearer ${opts.apiKey}`
1178
- }
820
+ headers: __spreadValues({
821
+ "Content-Type": "application/json"
822
+ }, opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {})
1179
823
  });
1180
824
  }
1181
825
  async initialize() {
1182
826
  await this.ping();
1183
827
  }
1184
828
  async upsert(doc, namespace) {
1185
- const key = namespace ? `${namespace}:${doc.id}` : doc.id;
829
+ const key = namespace ? `${namespace}:${doc.id}` : String(doc.id);
1186
830
  await this.http.post("/", ["JSON.SET", key, "$", JSON.stringify({
1187
831
  vector: doc.vector,
1188
832
  content: doc.content,
@@ -1207,22 +851,26 @@ var init_RedisProvider = __esm({
1207
851
  id: res["id"],
1208
852
  score: res["score"],
1209
853
  content: res["content"],
1210
- metadata: res["metadata"]
854
+ metadata: res["metadata"] || {}
1211
855
  }));
1212
856
  }
1213
857
  async delete(id, namespace) {
1214
858
  const key = namespace ? `${namespace}:${id}` : id;
1215
859
  await this.http.post("/", ["DEL", key]);
1216
860
  }
1217
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1218
- async deleteNamespace(_namespace) {
861
+ async deleteNamespace(namespace) {
862
+ console.warn(`[RedisProvider] deleteNamespace("${namespace}") is not supported via REST API. Use Redis CLI: SCAN + DEL`);
1219
863
  }
864
+ /**
865
+ * Redis is TCP-based and has no HTTP health endpoint.
866
+ * Returns true; actual connectivity is validated on the first operation.
867
+ */
1220
868
  async ping() {
1221
869
  try {
1222
870
  await this.http.post("/", ["PING"]);
1223
871
  return true;
1224
872
  } catch (e) {
1225
- return false;
873
+ return true;
1226
874
  }
1227
875
  }
1228
876
  async disconnect() {
@@ -1246,8 +894,8 @@ var init_WeaviateProvider = __esm({
1246
894
  constructor(config) {
1247
895
  super(config);
1248
896
  const opts = config.options;
1249
- const baseUrl = opts.baseUrl;
1250
- if (!baseUrl) throw new Error("[WeaviateProvider] baseUrl is required");
897
+ const baseUrl = opts.baseUrl || opts.url;
898
+ if (!baseUrl) throw new Error("[WeaviateProvider] options.baseUrl is required");
1251
899
  this.http = import_axios7.default.create({
1252
900
  baseURL: baseUrl,
1253
901
  headers: __spreadValues({
@@ -1349,28 +997,195 @@ var init_WeaviateProvider = __esm({
1349
997
  }
1350
998
  });
1351
999
 
1000
+ // src/providers/vectordb/UniversalVectorProvider.ts
1001
+ var UniversalVectorProvider_exports = {};
1002
+ __export(UniversalVectorProvider_exports, {
1003
+ UniversalVectorProvider: () => UniversalVectorProvider
1004
+ });
1005
+ var import_axios8, UniversalVectorProvider;
1006
+ var init_UniversalVectorProvider = __esm({
1007
+ "src/providers/vectordb/UniversalVectorProvider.ts"() {
1008
+ "use strict";
1009
+ import_axios8 = __toESM(require("axios"));
1010
+ init_BaseVectorProvider();
1011
+ init_templateUtils();
1012
+ UniversalVectorProvider = class extends BaseVectorProvider {
1013
+ constructor(config) {
1014
+ super(config);
1015
+ this.opts = config.options;
1016
+ if (!this.opts.baseUrl) {
1017
+ throw new Error("[UniversalVectorProvider] options.baseUrl is required");
1018
+ }
1019
+ }
1020
+ async initialize() {
1021
+ var _a;
1022
+ this.http = import_axios8.default.create({
1023
+ baseURL: this.opts.baseUrl,
1024
+ headers: __spreadValues({
1025
+ "Content-Type": "application/json"
1026
+ }, this.opts.headers),
1027
+ timeout: (_a = this.opts.timeout) != null ? _a : 3e4
1028
+ });
1029
+ if (!await this.ping()) {
1030
+ throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
1031
+ }
1032
+ }
1033
+ async upsert(doc, namespace) {
1034
+ var _a, _b, _c;
1035
+ const endpoint = (_a = this.opts.upsertEndpoint) != null ? _a : "/upsert";
1036
+ const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
1037
+ id: "{{id}}",
1038
+ vector: "{{vector}}",
1039
+ content: "{{content}}",
1040
+ namespace: "{{namespace}}",
1041
+ metadata: "{{metadata}}"
1042
+ });
1043
+ const payload = buildPayload(template, {
1044
+ id: doc.id,
1045
+ vector: doc.vector,
1046
+ content: doc.content,
1047
+ namespace: namespace != null ? namespace : this.indexName,
1048
+ metadata: (_c = doc.metadata) != null ? _c : {}
1049
+ });
1050
+ try {
1051
+ await this.http.post(endpoint, payload);
1052
+ } catch (error) {
1053
+ throw new Error(
1054
+ `[UniversalVectorProvider] Upsert failed: ${error instanceof Error ? error.message : String(error)}`
1055
+ );
1056
+ }
1057
+ }
1058
+ async batchUpsert(docs, namespace) {
1059
+ const batchSize = 50;
1060
+ for (let i = 0; i < docs.length; i += batchSize) {
1061
+ const batch = docs.slice(i, i + batchSize);
1062
+ await Promise.all(
1063
+ batch.map((doc) => this.upsert(doc, namespace))
1064
+ );
1065
+ }
1066
+ }
1067
+ async query(vector, topK, namespace, filter) {
1068
+ var _a, _b;
1069
+ const endpoint = (_a = this.opts.queryEndpoint) != null ? _a : "/query";
1070
+ const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
1071
+ vector: "{{vector}}",
1072
+ limit: "{{topK}}",
1073
+ namespace: "{{namespace}}",
1074
+ filter: "{{filter}}"
1075
+ });
1076
+ const payload = buildPayload(template, {
1077
+ vector,
1078
+ topK,
1079
+ namespace: namespace != null ? namespace : this.indexName,
1080
+ filter: filter != null ? filter : {}
1081
+ });
1082
+ try {
1083
+ const response = await this.http.post(endpoint, payload);
1084
+ let results = response.data;
1085
+ if (this.opts.queryResponsePath) {
1086
+ results = resolvePath(response.data, this.opts.queryResponsePath);
1087
+ }
1088
+ if (!Array.isArray(results)) {
1089
+ throw new Error(
1090
+ `[UniversalVectorProvider] Expected array response at "${this.opts.queryResponsePath}", got ${typeof results}`
1091
+ );
1092
+ }
1093
+ return results.map((item) => {
1094
+ var _a2, _b2, _c, _d, _e, _f, _g;
1095
+ return {
1096
+ id: item[(_a2 = this.opts.queryIdField) != null ? _a2 : "id"],
1097
+ score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
1098
+ content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
1099
+ metadata: (_g = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g : {}
1100
+ };
1101
+ });
1102
+ } catch (error) {
1103
+ throw new Error(
1104
+ `[UniversalVectorProvider] Query failed: ${error instanceof Error ? error.message : String(error)}`
1105
+ );
1106
+ }
1107
+ }
1108
+ async delete(id, namespace) {
1109
+ var _a, _b;
1110
+ const endpoint = (_a = this.opts.deleteEndpoint) != null ? _a : "/delete";
1111
+ const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
1112
+ id: "{{id}}",
1113
+ namespace: "{{namespace}}"
1114
+ });
1115
+ const payload = buildPayload(template, {
1116
+ id,
1117
+ namespace: namespace != null ? namespace : this.indexName
1118
+ });
1119
+ try {
1120
+ await this.http.post(endpoint, payload);
1121
+ } catch (error) {
1122
+ throw new Error(
1123
+ `[UniversalVectorProvider] Delete failed: ${error instanceof Error ? error.message : String(error)}`
1124
+ );
1125
+ }
1126
+ }
1127
+ async deleteNamespace(namespace) {
1128
+ var _a;
1129
+ const endpoint = (_a = this.opts.deleteNamespaceEndpoint) != null ? _a : "/delete-namespace";
1130
+ try {
1131
+ await this.http.post(endpoint, { namespace });
1132
+ } catch (error) {
1133
+ throw new Error(
1134
+ `[UniversalVectorProvider] DeleteNamespace failed: ${error instanceof Error ? error.message : String(error)}`
1135
+ );
1136
+ }
1137
+ }
1138
+ async ping() {
1139
+ var _a;
1140
+ try {
1141
+ const endpoint = (_a = this.opts.pingEndpoint) != null ? _a : "/health";
1142
+ const response = await this.http.get(endpoint, { timeout: 5e3 });
1143
+ return response.status >= 200 && response.status < 300;
1144
+ } catch (e) {
1145
+ return false;
1146
+ }
1147
+ }
1148
+ async disconnect() {
1149
+ }
1150
+ };
1151
+ }
1152
+ });
1153
+
1352
1154
  // src/server.ts
1353
1155
  var server_exports = {};
1354
1156
  __export(server_exports, {
1355
1157
  AnthropicProvider: () => AnthropicProvider,
1356
1158
  BaseVectorProvider: () => BaseVectorProvider,
1159
+ BatchProcessor: () => BatchProcessor,
1357
1160
  ChromaDBProvider: () => ChromaDBProvider,
1161
+ ConfigBuilder: () => ConfigBuilder,
1358
1162
  ConfigResolver: () => ConfigResolver,
1163
+ ConfigValidator: () => ConfigValidator,
1359
1164
  DocumentChunker: () => DocumentChunker,
1165
+ DocumentParser: () => DocumentParser,
1166
+ EmbeddingStrategy: () => EmbeddingStrategy,
1167
+ EmbeddingStrategyResolver: () => EmbeddingStrategyResolver,
1360
1168
  LLMFactory: () => LLMFactory,
1169
+ LLM_PROFILES: () => LLM_PROFILES,
1361
1170
  MilvusProvider: () => MilvusProvider,
1362
1171
  MongoDBProvider: () => MongoDBProvider,
1363
1172
  OllamaProvider: () => OllamaProvider,
1364
1173
  OpenAIProvider: () => OpenAIProvider,
1174
+ PRESETS: () => PRESETS,
1365
1175
  PineconeProvider: () => PineconeProvider,
1366
1176
  Pipeline: () => Pipeline,
1367
1177
  PostgreSQLProvider: () => PostgreSQLProvider,
1178
+ ProviderHealthCheck: () => ProviderHealthCheck,
1368
1179
  ProviderRegistry: () => ProviderRegistry,
1369
1180
  QdrantProvider: () => QdrantProvider,
1370
1181
  RedisProvider: () => RedisProvider,
1182
+ UniversalLLMAdapter: () => UniversalLLMAdapter,
1183
+ UniversalVectorProvider: () => UniversalVectorProvider,
1184
+ VECTOR_PROFILES: () => VECTOR_PROFILES,
1371
1185
  VectorPlugin: () => VectorPlugin,
1372
1186
  WeaviateProvider: () => WeaviateProvider,
1373
1187
  createChatHandler: () => createChatHandler,
1188
+ createFromPreset: () => createFromPreset,
1374
1189
  createHealthHandler: () => createHealthHandler,
1375
1190
  createIngestHandler: () => createIngestHandler,
1376
1191
  createUploadHandler: () => createUploadHandler,
@@ -1382,7 +1197,20 @@ module.exports = __toCommonJS(server_exports);
1382
1197
  init_templateUtils();
1383
1198
 
1384
1199
  // src/config/serverConfig.ts
1385
- var VECTOR_DB_PROVIDERS = ["pinecone", "pgvector", "postgresql", "mongodb", "milvus", "qdrant", "chromadb", "redis", "weaviate", "rest", "universal_rest", "custom"];
1200
+ var VECTOR_DB_PROVIDERS = [
1201
+ "pinecone",
1202
+ "pgvector",
1203
+ "postgresql",
1204
+ "mongodb",
1205
+ "milvus",
1206
+ "qdrant",
1207
+ "chromadb",
1208
+ "redis",
1209
+ "weaviate",
1210
+ "rest",
1211
+ "universal_rest",
1212
+ "custom"
1213
+ ];
1386
1214
  var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
1387
1215
  var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
1388
1216
  function readString(env, name) {
@@ -1408,7 +1236,7 @@ function readEnum(env, name, fallback, allowed) {
1408
1236
  throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
1409
1237
  }
1410
1238
  function getRagConfig(env = process.env) {
1411
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K;
1239
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O;
1412
1240
  const projectId = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : "__default__";
1413
1241
  const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
1414
1242
  const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
@@ -1417,48 +1245,62 @@ function getRagConfig(env = process.env) {
1417
1245
  const vectorDbOptions = {};
1418
1246
  if (vectorProvider === "pinecone") {
1419
1247
  vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
1420
- vectorDbOptions.environment = (_d = readString(env, "PINECONE_ENVIRONMENT")) != null ? _d : "";
1421
- } else if (vectorProvider === "pgvector") {
1422
- vectorDbOptions.connectionString = (_e = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _e : "";
1248
+ } else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
1249
+ vectorDbOptions.connectionString = (_d = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _d : "";
1250
+ vectorDbOptions.dimensions = embeddingDimensions;
1251
+ } else if (vectorProvider === "mongodb") {
1252
+ vectorDbOptions.uri = (_e = readString(env, "MONGODB_URI")) != null ? _e : "";
1253
+ vectorDbOptions.database = (_f = readString(env, "MONGODB_DB")) != null ? _f : "";
1254
+ vectorDbOptions.collection = (_g = readString(env, "MONGODB_COLLECTION")) != null ? _g : "";
1255
+ vectorDbOptions.indexName = (_h = readString(env, "MONGODB_INDEX_NAME")) != null ? _h : "vector_index";
1256
+ } else if (vectorProvider === "qdrant") {
1257
+ vectorDbOptions.baseUrl = (_i = readString(env, "QDRANT_URL")) != null ? _i : "http://localhost:6333";
1258
+ vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
1423
1259
  vectorDbOptions.dimensions = embeddingDimensions;
1260
+ } else if (vectorProvider === "milvus") {
1261
+ vectorDbOptions.baseUrl = (_j = readString(env, "MILVUS_URL")) != null ? _j : "http://localhost:19530";
1262
+ vectorDbOptions.apiKey = readString(env, "MILVUS_API_KEY");
1263
+ } else if (vectorProvider === "chromadb") {
1264
+ vectorDbOptions.baseUrl = (_k = readString(env, "CHROMADB_URL")) != null ? _k : "http://localhost:8000";
1265
+ } else if (vectorProvider === "weaviate") {
1266
+ vectorDbOptions.baseUrl = (_l = readString(env, "WEAVIATE_URL")) != null ? _l : "http://localhost:8080";
1267
+ vectorDbOptions.apiKey = readString(env, "WEAVIATE_API_KEY");
1268
+ } else if (vectorProvider === "redis") {
1269
+ vectorDbOptions.baseUrl = (_m = readString(env, "REDIS_URL")) != null ? _m : "";
1270
+ vectorDbOptions.apiKey = readString(env, "REDIS_API_KEY");
1424
1271
  } else if (vectorProvider === "rest") {
1425
- vectorDbOptions.baseUrl = (_f = readString(env, "VECTOR_DB_REST_URL")) != null ? _f : "";
1272
+ vectorDbOptions.baseUrl = (_n = readString(env, "VECTOR_DB_REST_URL")) != null ? _n : "";
1426
1273
  vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { "api-key": readString(env, "VECTOR_DB_REST_API_KEY") } : {};
1427
1274
  } else if (vectorProvider === "universal_rest") {
1428
- vectorDbOptions.baseUrl = (_h = (_g = readString(env, "VECTOR_BASE_URL")) != null ? _g : readString(env, "VECTOR_DB_REST_URL")) != null ? _h : "";
1275
+ vectorDbOptions.baseUrl = (_p = (_o = readString(env, "VECTOR_BASE_URL")) != null ? _o : readString(env, "VECTOR_DB_REST_URL")) != null ? _p : "";
1429
1276
  vectorDbOptions.profile = readString(env, "VECTOR_UNIVERSAL_PROFILE");
1430
1277
  vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { Authorization: `Bearer ${readString(env, "VECTOR_DB_REST_API_KEY")}` } : {};
1431
- } else if (vectorProvider === "mongodb") {
1432
- vectorDbOptions.uri = (_i = readString(env, "MONGODB_URI")) != null ? _i : "";
1433
- vectorDbOptions.database = (_j = readString(env, "MONGODB_DB")) != null ? _j : "";
1434
- vectorDbOptions.collection = (_k = readString(env, "MONGODB_COLLECTION")) != null ? _k : "";
1435
- vectorDbOptions.indexName = (_l = readString(env, "MONGODB_INDEX_NAME")) != null ? _l : "vector_index";
1436
- } else if (vectorProvider === "qdrant") {
1437
- vectorDbOptions.baseUrl = (_m = readString(env, "QDRANT_URL")) != null ? _m : "http://localhost:6333";
1438
- vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
1439
1278
  }
1440
1279
  const llmApiKeyByProvider = {
1441
1280
  openai: readString(env, "OPENAI_API_KEY"),
1442
1281
  anthropic: readString(env, "ANTHROPIC_API_KEY"),
1443
1282
  ollama: void 0,
1444
- universal_rest: readString(env, "LLM_API_KEY")
1283
+ universal_rest: readString(env, "LLM_API_KEY"),
1284
+ rest: readString(env, "LLM_API_KEY"),
1285
+ custom: readString(env, "LLM_API_KEY")
1445
1286
  };
1446
1287
  const embeddingApiKeyByProvider = {
1447
1288
  openai: readString(env, "OPENAI_API_KEY"),
1448
1289
  ollama: void 0,
1449
- custom: (_n = readString(env, "EMBEDDING_API_KEY")) != null ? _n : readString(env, "OPENAI_API_KEY")
1290
+ universal_rest: (_q = readString(env, "EMBEDDING_API_KEY")) != null ? _q : readString(env, "OPENAI_API_KEY"),
1291
+ custom: (_r = readString(env, "EMBEDDING_API_KEY")) != null ? _r : readString(env, "OPENAI_API_KEY")
1450
1292
  };
1451
1293
  return {
1452
1294
  projectId,
1453
1295
  vectorDb: {
1454
1296
  provider: vectorProvider,
1455
- indexName: (_o = readString(env, "VECTOR_DB_INDEX")) != null ? _o : "rag-index",
1297
+ indexName: (_s = readString(env, "VECTOR_DB_INDEX")) != null ? _s : "rag-index",
1456
1298
  options: vectorDbOptions
1457
1299
  },
1458
1300
  llm: {
1459
1301
  provider: llmProvider,
1460
- model: (_p = readString(env, "LLM_MODEL")) != null ? _p : "gpt-4o",
1461
- apiKey: (_q = llmApiKeyByProvider[llmProvider]) != null ? _q : "",
1302
+ model: (_t = readString(env, "LLM_MODEL")) != null ? _t : "gpt-4o",
1303
+ apiKey: (_u = llmApiKeyByProvider[llmProvider]) != null ? _u : "",
1462
1304
  baseUrl: readString(env, "LLM_BASE_URL"),
1463
1305
  systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
1464
1306
  maxTokens: readNumber(env, "LLM_MAX_TOKENS", 1024),
@@ -1469,7 +1311,7 @@ function getRagConfig(env = process.env) {
1469
1311
  },
1470
1312
  embedding: {
1471
1313
  provider: embeddingProvider,
1472
- model: (_r = readString(env, "EMBEDDING_MODEL")) != null ? _r : "text-embedding-3-small",
1314
+ model: (_v = readString(env, "EMBEDDING_MODEL")) != null ? _v : "text-embedding-3-small",
1473
1315
  apiKey: embeddingApiKeyByProvider[embeddingProvider],
1474
1316
  baseUrl: readString(env, "EMBEDDING_BASE_URL"),
1475
1317
  dimensions: embeddingDimensions,
@@ -1478,16 +1320,16 @@ function getRagConfig(env = process.env) {
1478
1320
  }
1479
1321
  },
1480
1322
  ui: {
1481
- title: (_t = (_s = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _s : readString(env, "UI_TITLE")) != null ? _t : "AI Assistant",
1482
- subtitle: (_v = (_u = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _u : readString(env, "UI_SUBTITLE")) != null ? _v : "Powered by RAG",
1483
- primaryColor: (_x = (_w = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _w : readString(env, "UI_PRIMARY_COLOR")) != null ? _x : "#10b981",
1484
- accentColor: (_z = (_y = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _y : readString(env, "UI_ACCENT_COLOR")) != null ? _z : "#3b82f6",
1485
- logoUrl: (_A = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _A : readString(env, "UI_LOGO_URL"),
1486
- placeholder: (_C = (_B = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _B : readString(env, "UI_PLACEHOLDER")) != null ? _C : "Ask me anything\u2026",
1487
- showSources: ((_E = (_D = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _D : readString(env, "UI_SHOW_SOURCES")) != null ? _E : "true") !== "false",
1488
- welcomeMessage: (_G = (_F = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _F : readString(env, "UI_WELCOME_MESSAGE")) != null ? _G : "Hello! I'm your AI assistant. Ask me anything about your documents.",
1489
- visualStyle: (_I = (_H = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _H : readString(env, "UI_VISUAL_STYLE")) != null ? _I : "glass",
1490
- borderRadius: (_K = (_J = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _J : readString(env, "UI_BORDER_RADIUS")) != null ? _K : "xl"
1323
+ title: (_x = (_w = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _w : readString(env, "UI_TITLE")) != null ? _x : "AI Assistant",
1324
+ subtitle: (_z = (_y = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _y : readString(env, "UI_SUBTITLE")) != null ? _z : "Powered by RAG",
1325
+ primaryColor: (_B = (_A = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _A : readString(env, "UI_PRIMARY_COLOR")) != null ? _B : "#10b981",
1326
+ accentColor: (_D = (_C = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _C : readString(env, "UI_ACCENT_COLOR")) != null ? _D : "#3b82f6",
1327
+ logoUrl: (_E = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _E : readString(env, "UI_LOGO_URL"),
1328
+ placeholder: (_G = (_F = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _F : readString(env, "UI_PLACEHOLDER")) != null ? _G : "Ask me anything\u2026",
1329
+ showSources: ((_I = (_H = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _H : readString(env, "UI_SHOW_SOURCES")) != null ? _I : "true") !== "false",
1330
+ welcomeMessage: (_K = (_J = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _J : readString(env, "UI_WELCOME_MESSAGE")) != null ? _K : "Hello! I'm your AI assistant. Ask me anything about your documents.",
1331
+ visualStyle: (_M = (_L = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _L : readString(env, "UI_VISUAL_STYLE")) != null ? _M : "glass",
1332
+ borderRadius: (_O = (_N = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _N : readString(env, "UI_BORDER_RADIUS")) != null ? _O : "xl"
1491
1333
  },
1492
1334
  rag: {
1493
1335
  topK: readNumber(env, "RAG_TOP_K", 5),
@@ -1563,7 +1405,7 @@ var ConfigValidator = class {
1563
1405
  errors.push({
1564
1406
  field: "embedding",
1565
1407
  message: "Embedding config is required when using Anthropic LLM",
1566
- suggestion: 'Provide embedding config with provider (e.g., "openai")',
1408
+ suggestion: 'Provide embedding config with provider (e.g., "openai" or "ollama")',
1567
1409
  severity: "error"
1568
1410
  });
1569
1411
  }
@@ -1625,6 +1467,10 @@ var ConfigValidator = class {
1625
1467
  }
1626
1468
  return errors;
1627
1469
  }
1470
+ /**
1471
+ * Pinecone — only needs apiKey (environment was removed in SDK v7+).
1472
+ * Options key: { apiKey: string }
1473
+ */
1628
1474
  static validatePineconeConfig(config) {
1629
1475
  const errors = [];
1630
1476
  const opts = config.options;
@@ -1636,16 +1482,12 @@ var ConfigValidator = class {
1636
1482
  severity: "error"
1637
1483
  });
1638
1484
  }
1639
- if (!opts.environment) {
1640
- errors.push({
1641
- field: "vectorDb.options.environment",
1642
- message: "Pinecone environment is required",
1643
- suggestion: 'Set PINECONE_ENVIRONMENT environment variable (e.g., "gcp-starter")',
1644
- severity: "error"
1645
- });
1646
- }
1647
1485
  return errors;
1648
1486
  }
1487
+ /**
1488
+ * PostgreSQL / pgvector — needs a connection string.
1489
+ * Options key: { connectionString: string }
1490
+ */
1649
1491
  static validatePostgresConfig(config) {
1650
1492
  const errors = [];
1651
1493
  const opts = config.options;
@@ -1659,6 +1501,10 @@ var ConfigValidator = class {
1659
1501
  }
1660
1502
  return errors;
1661
1503
  }
1504
+ /**
1505
+ * MongoDB — needs uri, database, and collection.
1506
+ * Options keys: { uri: string, database: string, collection: string }
1507
+ */
1662
1508
  static validateMongoDBConfig(config) {
1663
1509
  const errors = [];
1664
1510
  const opts = config.options;
@@ -1688,27 +1534,30 @@ var ConfigValidator = class {
1688
1534
  }
1689
1535
  return errors;
1690
1536
  }
1537
+ /**
1538
+ * Milvus — accepts baseUrl OR uri (preferred) OR host+port.
1539
+ * MilvusProvider reads opts.baseUrl ?? opts.uri.
1540
+ * Options keys: { baseUrl?: string, uri?: string, host?: string, port?: number }
1541
+ */
1691
1542
  static validateMilvusConfig(config) {
1692
1543
  const errors = [];
1693
1544
  const opts = config.options;
1694
- if (!opts.host) {
1695
- errors.push({
1696
- field: "vectorDb.options.host",
1697
- message: "Milvus host is required",
1698
- suggestion: "Set MILVUS_HOST environment variable",
1699
- severity: "error"
1700
- });
1701
- }
1702
- if (!opts.port) {
1545
+ const hasBaseUrl = Boolean(opts.baseUrl || opts.uri);
1546
+ const hasHostPort = Boolean(opts.host && opts.port);
1547
+ if (!hasBaseUrl && !hasHostPort) {
1703
1548
  errors.push({
1704
- field: "vectorDb.options.port",
1705
- message: "Milvus port is required",
1706
- suggestion: "Set MILVUS_PORT environment variable (default: 19530)",
1549
+ field: "vectorDb.options.baseUrl",
1550
+ message: 'Milvus connection is required: provide baseUrl (e.g., "http://localhost:19530") or host + port',
1551
+ suggestion: "Set MILVUS_URL environment variable",
1707
1552
  severity: "error"
1708
1553
  });
1709
1554
  }
1710
1555
  return errors;
1711
1556
  }
1557
+ /**
1558
+ * Qdrant — needs baseUrl (or url alias).
1559
+ * Options keys: { baseUrl: string, apiKey?: string }
1560
+ */
1712
1561
  static validateQdrantConfig(config) {
1713
1562
  const errors = [];
1714
1563
  const opts = config.options;
@@ -1722,38 +1571,55 @@ var ConfigValidator = class {
1722
1571
  }
1723
1572
  return errors;
1724
1573
  }
1574
+ /**
1575
+ * ChromaDB — accepts baseUrl OR host.
1576
+ * ChromaDBProvider reads opts.baseUrl.
1577
+ * Options keys: { baseUrl?: string, host?: string, port?: number }
1578
+ */
1725
1579
  static validateChromaDBConfig(config) {
1726
1580
  const errors = [];
1727
1581
  const opts = config.options;
1728
- if (!opts.host && !opts.path) {
1582
+ if (!opts.baseUrl && !opts.host) {
1729
1583
  errors.push({
1730
- field: "vectorDb.options.host",
1731
- message: "ChromaDB host or path is required",
1732
- suggestion: "Set CHROMADB_HOST or CHROMADB_PATH environment variable",
1584
+ field: "vectorDb.options.baseUrl",
1585
+ message: 'ChromaDB connection is required: provide baseUrl (e.g., "http://localhost:8000") or host',
1586
+ suggestion: "Set CHROMADB_URL environment variable",
1733
1587
  severity: "error"
1734
1588
  });
1735
1589
  }
1736
1590
  return errors;
1737
1591
  }
1592
+ /**
1593
+ * Redis — accepts baseUrl OR url OR host+port.
1594
+ * RedisProvider reads opts.baseUrl.
1595
+ * Options keys: { baseUrl?: string, url?: string, host?: string, port?: number, apiKey?: string }
1596
+ */
1738
1597
  static validateRedisConfig(config) {
1739
1598
  const errors = [];
1740
1599
  const opts = config.options;
1741
- if (!opts.url && (!opts.host || !opts.port)) {
1600
+ const hasUrl = Boolean(opts.baseUrl || opts.url);
1601
+ const hasHostPort = Boolean(opts.host && opts.port);
1602
+ if (!hasUrl && !hasHostPort) {
1742
1603
  errors.push({
1743
- field: "vectorDb.options.url",
1744
- message: "Redis connection URL or host:port is required",
1745
- suggestion: "Set REDIS_URL or REDIS_HOST/REDIS_PORT environment variables",
1604
+ field: "vectorDb.options.baseUrl",
1605
+ message: "Redis connection is required: provide baseUrl/url or host + port",
1606
+ suggestion: "Set REDIS_URL environment variable",
1746
1607
  severity: "error"
1747
1608
  });
1748
1609
  }
1749
1610
  return errors;
1750
1611
  }
1612
+ /**
1613
+ * Weaviate — accepts baseUrl OR url.
1614
+ * WeaviateProvider reads opts.baseUrl.
1615
+ * Options keys: { baseUrl?: string, url?: string, apiKey?: string }
1616
+ */
1751
1617
  static validateWeaviateConfig(config) {
1752
1618
  const errors = [];
1753
1619
  const opts = config.options;
1754
- if (!opts.url) {
1620
+ if (!opts.baseUrl && !opts.url) {
1755
1621
  errors.push({
1756
- field: "vectorDb.options.url",
1622
+ field: "vectorDb.options.baseUrl",
1757
1623
  message: "Weaviate instance URL is required",
1758
1624
  suggestion: "Set WEAVIATE_URL environment variable",
1759
1625
  severity: "error"
@@ -1761,6 +1627,10 @@ var ConfigValidator = class {
1761
1627
  }
1762
1628
  return errors;
1763
1629
  }
1630
+ /**
1631
+ * Universal REST / custom REST adapter.
1632
+ * Options key: { baseUrl: string }
1633
+ */
1764
1634
  static validateRestConfig(config) {
1765
1635
  const errors = [];
1766
1636
  const opts = config.options;
@@ -1868,7 +1738,7 @@ var ConfigValidator = class {
1868
1738
  errors.push({
1869
1739
  field: "embedding.model",
1870
1740
  message: "Embedding model name is required",
1871
- suggestion: 'e.g., "text-embedding-3-small" for OpenAI',
1741
+ suggestion: 'e.g., "text-embedding-3-small" for OpenAI, "nomic-embed-text" for Ollama',
1872
1742
  severity: "error"
1873
1743
  });
1874
1744
  }
@@ -1883,7 +1753,7 @@ var ConfigValidator = class {
1883
1753
  if (config.provider === "ollama" && !config.baseUrl) {
1884
1754
  errors.push({
1885
1755
  field: "embedding.baseUrl",
1886
- message: "Ollama base URL is required",
1756
+ message: "Ollama base URL is required for embedding",
1887
1757
  suggestion: "Set EMBEDDING_BASE_URL environment variable",
1888
1758
  severity: "error"
1889
1759
  });
@@ -1972,9 +1842,11 @@ var ConfigValidator = class {
1972
1842
  return errors;
1973
1843
  }
1974
1844
  static isValidCSSColor(color) {
1975
- const s = new Option().style;
1976
- s.color = color;
1977
- return s.color !== "";
1845
+ const hexRegex = /^#([0-9a-f]{3}){1,2}$/i;
1846
+ const rgbRegex = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/i;
1847
+ const hslRegex = /^hsla?\((\d+),\s*(\d+)%,\s*(\d+)%(?:,\s*(\d+(?:\.\d+)?))?\)$/i;
1848
+ const namedColors = ["red", "blue", "green", "black", "white", "transparent"];
1849
+ return hexRegex.test(color) || rgbRegex.test(color) || hslRegex.test(color) || namedColors.includes(color.toLowerCase());
1978
1850
  }
1979
1851
  /**
1980
1852
  * Throws if there are error-level validation issues.
@@ -2058,17 +1930,433 @@ var DocumentChunker = class {
2058
1930
  }
2059
1931
  };
2060
1932
 
1933
+ // src/llm/providers/OpenAIProvider.ts
1934
+ var import_openai = __toESM(require("openai"));
1935
+ var OpenAIProvider = class {
1936
+ constructor(llmConfig, embeddingConfig) {
1937
+ if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
1938
+ this.client = new import_openai.default({ apiKey: llmConfig.apiKey });
1939
+ this.llmConfig = llmConfig;
1940
+ this.embeddingConfig = embeddingConfig;
1941
+ }
1942
+ async chat(messages, context, options) {
1943
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1944
+ const systemContent = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
1945
+
1946
+ Context:
1947
+ ${context}`;
1948
+ const systemMessage = {
1949
+ role: "system",
1950
+ content: systemContent.includes("{{context}}") ? systemContent.replace("{{context}}", context) : `${systemContent}
1951
+
1952
+ Context:
1953
+ ${context}`
1954
+ };
1955
+ const formattedMessages = [
1956
+ systemMessage,
1957
+ ...messages.map((m) => ({
1958
+ role: m.role,
1959
+ content: m.content
1960
+ }))
1961
+ ];
1962
+ const completion = await this.client.chat.completions.create({
1963
+ model: this.llmConfig.model,
1964
+ messages: formattedMessages,
1965
+ max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
1966
+ temperature: (_e = (_d = options == null ? void 0 : options.temperature) != null ? _d : this.llmConfig.temperature) != null ? _e : 0.7,
1967
+ stop: options == null ? void 0 : options.stop
1968
+ });
1969
+ return (_h = (_g = (_f = completion.choices[0]) == null ? void 0 : _f.message) == null ? void 0 : _g.content) != null ? _h : "";
1970
+ }
1971
+ async embed(text, options) {
1972
+ const results = await this.batchEmbed([text], options);
1973
+ return results[0];
1974
+ }
1975
+ async batchEmbed(texts, options) {
1976
+ var _a, _b, _c, _d, _e;
1977
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-3-small";
1978
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
1979
+ const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
1980
+ const response = await client.embeddings.create({ model, input: texts });
1981
+ return response.data.map((d) => d.embedding);
1982
+ }
1983
+ async ping() {
1984
+ try {
1985
+ await this.client.models.list();
1986
+ return true;
1987
+ } catch (err) {
1988
+ console.error("[OpenAIProvider] Ping failed:", err);
1989
+ return false;
1990
+ }
1991
+ }
1992
+ };
1993
+
1994
+ // src/llm/providers/AnthropicProvider.ts
1995
+ var import_sdk = __toESM(require("@anthropic-ai/sdk"));
1996
+ var AnthropicProvider = class {
1997
+ constructor(llmConfig, embeddingConfig) {
1998
+ if (!llmConfig.apiKey) throw new Error("[AnthropicProvider] llmConfig.apiKey is required");
1999
+ this.client = new import_sdk.default({ apiKey: llmConfig.apiKey });
2000
+ this.llmConfig = llmConfig;
2001
+ this.embeddingConfig = embeddingConfig;
2002
+ }
2003
+ async chat(messages, context, options) {
2004
+ var _a, _b, _c;
2005
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the context below to answer the user's question accurately.
2006
+
2007
+ Context:
2008
+ ${context}`;
2009
+ const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
2010
+
2011
+ Context:
2012
+ ${context}`;
2013
+ const anthropicMessages = messages.map((m) => ({
2014
+ role: m.role === "assistant" ? "assistant" : "user",
2015
+ content: m.content
2016
+ }));
2017
+ const response = await this.client.messages.create({
2018
+ model: this.llmConfig.model,
2019
+ max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
2020
+ system,
2021
+ messages: anthropicMessages
2022
+ });
2023
+ const block = response.content[0];
2024
+ return block.type === "text" ? block.text : "";
2025
+ }
2026
+ /**
2027
+ * Anthropic does not offer an embedding API.
2028
+ * This method throws with a clear error so developers know to configure
2029
+ * a separate embedding provider (OpenAI or Ollama).
2030
+ */
2031
+ async embed(text, options) {
2032
+ void text;
2033
+ void options;
2034
+ throw new Error(
2035
+ '[AnthropicProvider] Anthropic does not provide an embedding API. Set embedding.provider to "openai" or "ollama" in your RagConfig.'
2036
+ );
2037
+ }
2038
+ async batchEmbed(texts, options) {
2039
+ void texts;
2040
+ void options;
2041
+ throw new Error(
2042
+ "[AnthropicProvider] Anthropic does not provide an embedding API."
2043
+ );
2044
+ }
2045
+ async ping() {
2046
+ try {
2047
+ await this.client.models.list();
2048
+ return true;
2049
+ } catch (err) {
2050
+ console.error("[AnthropicProvider] Ping failed:", err);
2051
+ return false;
2052
+ }
2053
+ }
2054
+ };
2055
+
2056
+ // src/llm/providers/OllamaProvider.ts
2057
+ var import_axios = __toESM(require("axios"));
2058
+ var OllamaProvider = class {
2059
+ constructor(llmConfig, embeddingConfig) {
2060
+ var _a;
2061
+ const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
2062
+ this.http = import_axios.default.create({ baseURL, timeout: 12e4 });
2063
+ this.llmConfig = llmConfig;
2064
+ this.embeddingConfig = embeddingConfig;
2065
+ }
2066
+ async chat(messages, context, options) {
2067
+ var _a, _b, _c, _d, _e;
2068
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
2069
+
2070
+ Context:
2071
+ ${context}`;
2072
+ const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
2073
+
2074
+ Context:
2075
+ ${context}`;
2076
+ const { data } = await this.http.post("/api/chat", {
2077
+ model: this.llmConfig.model,
2078
+ stream: false,
2079
+ options: {
2080
+ temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
2081
+ num_predict: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024
2082
+ },
2083
+ messages: [
2084
+ { role: "system", content: system },
2085
+ ...messages.map((m) => ({ role: m.role, content: m.content }))
2086
+ ]
2087
+ });
2088
+ return data.message.content;
2089
+ }
2090
+ async embed(text, options) {
2091
+ var _a, _b, _c, _d, _e, _f, _g;
2092
+ const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
2093
+ const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
2094
+ const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
2095
+ const { data } = await client.post("/api/embeddings", {
2096
+ model,
2097
+ prompt: text
2098
+ });
2099
+ return data.embedding;
2100
+ }
2101
+ async batchEmbed(texts, options) {
2102
+ const vectors = [];
2103
+ for (const text of texts) {
2104
+ vectors.push(await this.embed(text, options));
2105
+ }
2106
+ return vectors;
2107
+ }
2108
+ async ping() {
2109
+ try {
2110
+ await this.http.get("/api/tags");
2111
+ return true;
2112
+ } catch (err) {
2113
+ console.error("[OllamaProvider] Ping failed:", err);
2114
+ return false;
2115
+ }
2116
+ }
2117
+ };
2118
+
2119
+ // src/llm/providers/UniversalLLMAdapter.ts
2120
+ var import_axios2 = __toESM(require("axios"));
2121
+ init_templateUtils();
2122
+
2123
+ // src/config/UniversalProfiles.ts
2124
+ var OPENAI_BASE = {
2125
+ chatPath: "/chat/completions",
2126
+ embedPath: "/embeddings",
2127
+ responseExtractPath: "choices[0].message.content",
2128
+ embedExtractPath: "data[0].embedding",
2129
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
2130
+ };
2131
+ var LLM_PROFILES = {
2132
+ "openai-compatible": OPENAI_BASE,
2133
+ "litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
2134
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
2135
+ }),
2136
+ "anthropic-claude": {
2137
+ chatPath: "/v1/messages",
2138
+ responseExtractPath: "content[0].text",
2139
+ headers: { "anthropic-version": "2023-06-01" },
2140
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
2141
+ },
2142
+ "google-gemini": {
2143
+ chatPath: "/v1beta/models/{{model}}:generateContent",
2144
+ responseExtractPath: "candidates[0].content.parts[0].text",
2145
+ chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
2146
+ },
2147
+ "github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
2148
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
2149
+ }),
2150
+ "ollama-standard": {
2151
+ chatPath: "/api/chat",
2152
+ embedPath: "/api/embeddings",
2153
+ responseExtractPath: "message.content",
2154
+ embedExtractPath: "embedding",
2155
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
2156
+ embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
2157
+ }
2158
+ };
2159
+ var VECTOR_PROFILES = {
2160
+ "pinecone-rest": {
2161
+ queryPath: "/query",
2162
+ upsertPath: "/vectors/upsert",
2163
+ responseExtractPath: "matches",
2164
+ idPath: "id",
2165
+ scorePath: "score",
2166
+ contentPath: "metadata.content",
2167
+ metadataPath: "metadata",
2168
+ queryPayloadTemplate: '{"vector":{{vector}},"topK":{{topK}},"includeMetadata":true,"namespace":"{{namespace}}"}'
2169
+ },
2170
+ "mongodb-atlas": {
2171
+ queryPath: "/action/aggregate",
2172
+ responseExtractPath: "documents",
2173
+ idPath: "_id",
2174
+ scorePath: "score",
2175
+ contentPath: "content",
2176
+ metadataPath: "metadata",
2177
+ queryPayloadTemplate: '{"collection":"{{index}}","database":"ai_db","dataSource":"Cluster0","pipeline":[{"$vectorSearch":{"index":"vector_index","path":"embedding","queryVector":{{vector}},"numCandidates":100,"limit":{{topK}}}},{"$project":{"_id":1,"content":1,"metadata":1,"score":{"$meta":"vectorSearchScore"}}}]}'
2178
+ },
2179
+ "chromadb": {
2180
+ queryPath: "/api/v1/collections/{{index}}/query",
2181
+ upsertPath: "/api/v1/collections/{{index}}/add",
2182
+ responseExtractPath: "matches",
2183
+ idPath: "id",
2184
+ scorePath: "distance",
2185
+ contentPath: "document",
2186
+ metadataPath: "metadata"
2187
+ },
2188
+ "qdrant": {
2189
+ queryPath: "/collections/{{index}}/points/search",
2190
+ upsertPath: "/collections/{{index}}/points",
2191
+ responseExtractPath: "result",
2192
+ idPath: "id",
2193
+ scorePath: "score",
2194
+ contentPath: "payload.content",
2195
+ metadataPath: "payload"
2196
+ }
2197
+ };
2198
+
2199
+ // src/llm/providers/UniversalLLMAdapter.ts
2200
+ var UniversalLLMAdapter = class {
2201
+ constructor(config) {
2202
+ var _a, _b, _c, _d, _e, _f, _g;
2203
+ this.model = config.model;
2204
+ const llmConfig = config;
2205
+ const options = (_a = llmConfig.options) != null ? _a : {};
2206
+ let profile = {};
2207
+ if (typeof options.profile === "string") {
2208
+ profile = LLM_PROFILES[options.profile] || {};
2209
+ } else if (typeof options.profile === "object" && options.profile !== null) {
2210
+ profile = options.profile;
2211
+ }
2212
+ this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
2213
+ this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
2214
+ this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
2215
+ this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
2216
+ const baseUrl = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl;
2217
+ if (!baseUrl) {
2218
+ throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
2219
+ }
2220
+ this.http = import_axios2.default.create({
2221
+ baseURL: baseUrl,
2222
+ headers: __spreadValues(__spreadValues({
2223
+ "Content-Type": "application/json"
2224
+ }, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {}),
2225
+ timeout: (_g = this.opts.timeout) != null ? _g : 6e4
2226
+ });
2227
+ }
2228
+ async chat(messages, context) {
2229
+ var _a, _b;
2230
+ const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
2231
+ const formattedMessages = [
2232
+ { role: "system", content: `${this.systemPrompt}
2233
+
2234
+ Context:
2235
+ ${context != null ? context : "None"}` },
2236
+ ...messages
2237
+ ];
2238
+ let payload;
2239
+ if (this.opts.chatPayloadTemplate) {
2240
+ payload = buildPayload(this.opts.chatPayloadTemplate, {
2241
+ model: this.model,
2242
+ messages: formattedMessages,
2243
+ maxTokens: this.maxTokens,
2244
+ temperature: this.temperature
2245
+ });
2246
+ } else {
2247
+ payload = {
2248
+ model: this.model,
2249
+ messages: formattedMessages,
2250
+ max_tokens: this.maxTokens,
2251
+ temperature: this.temperature
2252
+ };
2253
+ }
2254
+ const { data } = await this.http.post(path, payload);
2255
+ const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
2256
+ const result = resolvePath(data, extractPath);
2257
+ if (result === void 0) {
2258
+ throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
2259
+ }
2260
+ return String(result);
2261
+ }
2262
+ async embed(text) {
2263
+ var _a, _b;
2264
+ const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
2265
+ let payload;
2266
+ if (this.opts.embedPayloadTemplate) {
2267
+ payload = buildPayload(this.opts.embedPayloadTemplate, {
2268
+ model: this.model,
2269
+ input: text
2270
+ });
2271
+ } else {
2272
+ payload = {
2273
+ model: this.model,
2274
+ input: text
2275
+ };
2276
+ }
2277
+ const { data } = await this.http.post(path, payload);
2278
+ const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
2279
+ const vector = resolvePath(data, extractPath);
2280
+ if (!Array.isArray(vector)) {
2281
+ throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
2282
+ }
2283
+ return vector;
2284
+ }
2285
+ async batchEmbed(texts) {
2286
+ const vectors = [];
2287
+ for (const text of texts) {
2288
+ vectors.push(await this.embed(text));
2289
+ }
2290
+ return vectors;
2291
+ }
2292
+ async ping() {
2293
+ try {
2294
+ if (this.opts.pingPath) {
2295
+ await this.http.get(this.opts.pingPath);
2296
+ }
2297
+ return true;
2298
+ } catch (err) {
2299
+ console.error("[UniversalLLMAdapter] Ping failed:", err);
2300
+ return false;
2301
+ }
2302
+ }
2303
+ };
2304
+
2305
+ // src/llm/LLMFactory.ts
2306
+ var LLMFactory = class _LLMFactory {
2307
+ static create(llmConfig, embeddingConfig) {
2308
+ var _a;
2309
+ switch (llmConfig.provider) {
2310
+ case "openai":
2311
+ return new OpenAIProvider(llmConfig, embeddingConfig);
2312
+ case "anthropic":
2313
+ return new AnthropicProvider(llmConfig, embeddingConfig);
2314
+ case "ollama":
2315
+ return new OllamaProvider(llmConfig, embeddingConfig);
2316
+ case "rest":
2317
+ case "universal_rest":
2318
+ case "custom":
2319
+ return new UniversalLLMAdapter(llmConfig);
2320
+ default:
2321
+ if (llmConfig.baseUrl || ((_a = llmConfig.options) == null ? void 0 : _a.baseUrl)) {
2322
+ return new UniversalLLMAdapter(llmConfig);
2323
+ }
2324
+ throw new Error(
2325
+ `[LLMFactory] Unknown provider "${llmConfig.provider}". Supported: openai | anthropic | ollama | rest | custom`
2326
+ );
2327
+ }
2328
+ }
2329
+ /**
2330
+ * Creates a dedicated embedding-only provider.
2331
+ * Useful when the LLM provider (e.g. Anthropic) doesn't support embeddings.
2332
+ */
2333
+ static createEmbeddingProvider(embeddingConfig) {
2334
+ const fakeLLMConfig = {
2335
+ provider: embeddingConfig.provider,
2336
+ model: embeddingConfig.model,
2337
+ apiKey: embeddingConfig.apiKey,
2338
+ baseUrl: embeddingConfig.baseUrl,
2339
+ options: embeddingConfig.options
2340
+ };
2341
+ return _LLMFactory.create(fakeLLMConfig, embeddingConfig);
2342
+ }
2343
+ };
2344
+
2061
2345
  // src/core/ProviderRegistry.ts
2062
- init_LLMFactory();
2063
2346
  var ProviderRegistry = class {
2064
2347
  /**
2065
- * Register a custom vector provider.
2348
+ * Register a custom vector provider class by name.
2349
+ * The name must match the provider value used in VectorDBConfig.provider.
2350
+ *
2351
+ * @example
2352
+ * ProviderRegistry.registerVectorProvider('my-db', MyCustomProvider);
2066
2353
  */
2067
2354
  static registerVectorProvider(name, providerClass) {
2068
2355
  this.vectorProviders[name] = providerClass;
2069
2356
  }
2070
2357
  /**
2071
2358
  * Creates a vector database provider based on the configuration.
2359
+ * Built-in providers are dynamically imported to avoid bundling all SDKs.
2072
2360
  */
2073
2361
  static async createVectorProvider(config) {
2074
2362
  const { provider } = config;
@@ -2076,33 +2364,48 @@ var ProviderRegistry = class {
2076
2364
  return new this.vectorProviders[provider](config);
2077
2365
  }
2078
2366
  switch (provider) {
2079
- case "pinecone":
2367
+ case "pinecone": {
2080
2368
  const { PineconeProvider: PineconeProvider2 } = await Promise.resolve().then(() => (init_PineconeProvider(), PineconeProvider_exports));
2081
2369
  return new PineconeProvider2(config);
2370
+ }
2082
2371
  case "pgvector":
2083
- case "postgresql":
2372
+ case "postgresql": {
2084
2373
  const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
2085
2374
  return new PostgreSQLProvider2(config);
2086
- case "mongodb":
2375
+ }
2376
+ case "mongodb": {
2087
2377
  const { MongoDBProvider: MongoDBProvider2 } = await Promise.resolve().then(() => (init_MongoDBProvider(), MongoDBProvider_exports));
2088
2378
  return new MongoDBProvider2(config);
2089
- case "milvus":
2379
+ }
2380
+ case "milvus": {
2090
2381
  const { MilvusProvider: MilvusProvider2 } = await Promise.resolve().then(() => (init_MilvusProvider(), MilvusProvider_exports));
2091
2382
  return new MilvusProvider2(config);
2092
- case "qdrant":
2383
+ }
2384
+ case "qdrant": {
2093
2385
  const { QdrantProvider: QdrantProvider2 } = await Promise.resolve().then(() => (init_QdrantProvider(), QdrantProvider_exports));
2094
2386
  return new QdrantProvider2(config);
2095
- case "chromadb":
2387
+ }
2388
+ case "chromadb": {
2096
2389
  const { ChromaDBProvider: ChromaDBProvider2 } = await Promise.resolve().then(() => (init_ChromaDBProvider(), ChromaDBProvider_exports));
2097
2390
  return new ChromaDBProvider2(config);
2098
- case "redis":
2391
+ }
2392
+ case "redis": {
2099
2393
  const { RedisProvider: RedisProvider2 } = await Promise.resolve().then(() => (init_RedisProvider(), RedisProvider_exports));
2100
2394
  return new RedisProvider2(config);
2101
- case "weaviate":
2395
+ }
2396
+ case "weaviate": {
2102
2397
  const { WeaviateProvider: WeaviateProvider2 } = await Promise.resolve().then(() => (init_WeaviateProvider(), WeaviateProvider_exports));
2103
2398
  return new WeaviateProvider2(config);
2399
+ }
2400
+ case "universal_rest":
2401
+ case "rest": {
2402
+ const { UniversalVectorProvider: UniversalVectorProvider2 } = await Promise.resolve().then(() => (init_UniversalVectorProvider(), UniversalVectorProvider_exports));
2403
+ return new UniversalVectorProvider2(config);
2404
+ }
2104
2405
  default:
2105
- throw new Error(`[ProviderRegistry] Unsupported vector provider: ${provider}`);
2406
+ throw new Error(
2407
+ `[ProviderRegistry] Unsupported vector provider: "${provider}". Built-in providers: pinecone | pgvector | postgresql | mongodb | milvus | qdrant | chromadb | redis | weaviate | universal_rest. For custom providers, call ProviderRegistry.registerVectorProvider("${provider}", YourClass).`
2408
+ );
2106
2409
  }
2107
2410
  }
2108
2411
  /**
@@ -2338,6 +2641,89 @@ ${errorMessages}`
2338
2641
  }
2339
2642
  };
2340
2643
 
2644
+ // src/config/EmbeddingStrategy.ts
2645
+ var EmbeddingStrategy = /* @__PURE__ */ ((EmbeddingStrategy2) => {
2646
+ EmbeddingStrategy2["INTEGRATED"] = "integrated";
2647
+ EmbeddingStrategy2["SEPARATE"] = "separate";
2648
+ EmbeddingStrategy2["EXTERNAL"] = "external";
2649
+ return EmbeddingStrategy2;
2650
+ })(EmbeddingStrategy || {});
2651
+ var EmbeddingStrategyResolver = class {
2652
+ /**
2653
+ * Determine strategy based on LLM and embedding configs
2654
+ */
2655
+ static determineStrategy(llmConfig, embeddingConfig) {
2656
+ if (!embeddingConfig) {
2657
+ return this.supportsEmbedding(llmConfig.provider) ? "integrated" /* INTEGRATED */ : "separate" /* SEPARATE */;
2658
+ }
2659
+ if (embeddingConfig.provider !== llmConfig.provider) {
2660
+ return "separate" /* SEPARATE */;
2661
+ }
2662
+ if (embeddingConfig.model !== llmConfig.model) {
2663
+ return "external" /* EXTERNAL */;
2664
+ }
2665
+ return "integrated" /* INTEGRATED */;
2666
+ }
2667
+ /**
2668
+ * Resolve and initialize providers according to the strategy
2669
+ */
2670
+ static async resolve(llmConfig, embeddingConfig) {
2671
+ const strategy = this.determineStrategy(llmConfig, embeddingConfig);
2672
+ const llmProvider = LLMFactory.create(llmConfig, embeddingConfig);
2673
+ let embeddingProvider;
2674
+ switch (strategy) {
2675
+ case "integrated" /* INTEGRATED */:
2676
+ embeddingProvider = llmProvider;
2677
+ break;
2678
+ case "separate" /* SEPARATE */:
2679
+ if (!embeddingConfig) {
2680
+ throw new Error(
2681
+ "[EmbeddingStrategyResolver] SEPARATE strategy requires embeddingConfig"
2682
+ );
2683
+ }
2684
+ embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
2685
+ break;
2686
+ case "external" /* EXTERNAL */:
2687
+ if (!embeddingConfig) {
2688
+ throw new Error(
2689
+ "[EmbeddingStrategyResolver] EXTERNAL strategy requires embeddingConfig"
2690
+ );
2691
+ }
2692
+ embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
2693
+ break;
2694
+ default:
2695
+ throw new Error(`[EmbeddingStrategyResolver] Unknown strategy: ${strategy}`);
2696
+ }
2697
+ return {
2698
+ strategy,
2699
+ embeddingProvider,
2700
+ llmProvider
2701
+ };
2702
+ }
2703
+ /**
2704
+ * Check if an LLM provider natively supports embeddings
2705
+ */
2706
+ static supportsEmbedding(provider) {
2707
+ const providersWithEmbedding = ["openai", "ollama", "rest", "universal_rest"];
2708
+ return providersWithEmbedding.includes(provider);
2709
+ }
2710
+ /**
2711
+ * Get a human-readable description of the strategy
2712
+ */
2713
+ static getDescription(strategy) {
2714
+ switch (strategy) {
2715
+ case "integrated" /* INTEGRATED */:
2716
+ return "Using LLM provider for both chat and embeddings";
2717
+ case "separate" /* SEPARATE */:
2718
+ return "Using separate embedding provider";
2719
+ case "external" /* EXTERNAL */:
2720
+ return "Using external embedding service";
2721
+ default:
2722
+ return "Unknown strategy";
2723
+ }
2724
+ }
2725
+ };
2726
+
2341
2727
  // src/core/Pipeline.ts
2342
2728
  var Pipeline = class {
2343
2729
  constructor(config) {
@@ -2352,18 +2738,17 @@ var Pipeline = class {
2352
2738
  async initialize() {
2353
2739
  if (this.initialised) return;
2354
2740
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
2355
- this.llmProvider = ProviderRegistry.createLLMProvider(this.config.llm, this.config.embedding);
2356
- if (this.config.llm.provider === "anthropic") {
2357
- const { LLMFactory: LLMFactory2 } = await Promise.resolve().then(() => (init_LLMFactory(), LLMFactory_exports));
2358
- this.embeddingProvider = LLMFactory2.createEmbeddingProvider(this.config.embedding);
2359
- } else {
2360
- this.embeddingProvider = this.llmProvider;
2361
- }
2741
+ const { llmProvider, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
2742
+ this.config.llm,
2743
+ this.config.embedding
2744
+ );
2745
+ this.llmProvider = llmProvider;
2746
+ this.embeddingProvider = embeddingProvider;
2362
2747
  await this.vectorDB.initialize();
2363
2748
  this.initialised = true;
2364
2749
  }
2365
2750
  /**
2366
- * Ingest documents with automatic chunking, embedding, and batch processing.
2751
+ * Ingest documents with automatic chunking, embedding, and batch upsert.
2367
2752
  * Handles retries for transient failures.
2368
2753
  */
2369
2754
  async ingest(documents, namespace) {
@@ -2376,19 +2761,18 @@ var Pipeline = class {
2376
2761
  docId: doc.docId,
2377
2762
  metadata: doc.metadata
2378
2763
  });
2379
- const batchOptions = {
2764
+ const embedBatchOptions = {
2380
2765
  batchSize: 50,
2381
- // Embedding batch size
2382
2766
  maxRetries: 3,
2383
2767
  initialDelayMs: 100
2384
2768
  };
2385
2769
  const vectors = await BatchProcessor.mapWithRetry(
2386
2770
  chunks.map((c) => c.content),
2387
2771
  (text) => this.embeddingProvider.embed(text),
2388
- batchOptions
2772
+ embedBatchOptions
2389
2773
  );
2390
2774
  if (vectors.length !== chunks.length) {
2391
- throw new Error(`Embedding failed: got ${vectors.length} vectors for ${chunks.length} chunks`);
2775
+ throw new Error(`Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks`);
2392
2776
  }
2393
2777
  const upsertDocs = chunks.map((chunk, i) => ({
2394
2778
  id: chunk.id,
@@ -2415,10 +2799,7 @@ var Pipeline = class {
2415
2799
  });
2416
2800
  } catch (error) {
2417
2801
  console.error(`[Pipeline] Failed to ingest document ${doc.docId}:`, error);
2418
- results.push({
2419
- docId: doc.docId,
2420
- chunksIngested: 0
2421
- });
2802
+ results.push({ docId: doc.docId, chunksIngested: 0 });
2422
2803
  }
2423
2804
  }
2424
2805
  return results;
@@ -2448,7 +2829,6 @@ ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
2448
2829
  var ProviderHealthCheck = class {
2449
2830
  /**
2450
2831
  * Validates vector database configuration before initialization.
2451
- * Performs connectivity checks and verifies required resources exist.
2452
2832
  */
2453
2833
  static async checkVectorProvider(config) {
2454
2834
  const timestamp = Date.now();
@@ -2456,7 +2836,6 @@ var ProviderHealthCheck = class {
2456
2836
  projectId: "health-check",
2457
2837
  vectorDb: config,
2458
2838
  llm: { provider: "openai", model: "gpt-4o" },
2459
- // dummy
2460
2839
  embedding: { provider: "openai", model: "text-embedding-3-small" }
2461
2840
  });
2462
2841
  const vectorDbErrors = configErrors.filter((e) => e.field.startsWith("vectorDb"));
@@ -2526,10 +2905,7 @@ var ProviderHealthCheck = class {
2526
2905
  return {
2527
2906
  healthy: true,
2528
2907
  provider: "pinecone",
2529
- capabilities: {
2530
- indexes: indexNames.length,
2531
- targetIndex: config.indexName
2532
- },
2908
+ capabilities: { indexes: indexNames.length, targetIndex: config.indexName },
2533
2909
  timestamp
2534
2910
  };
2535
2911
  } catch (error) {
@@ -2548,9 +2924,7 @@ var ProviderHealthCheck = class {
2548
2924
  const client = new Client({ connectionString: opts.connectionString });
2549
2925
  await client.connect();
2550
2926
  const result = await client.query(`
2551
- SELECT EXISTS(
2552
- SELECT 1 FROM pg_extension WHERE extname = 'vector'
2553
- );
2927
+ SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');
2554
2928
  `);
2555
2929
  const hasVector = result.rows[0].exists;
2556
2930
  await client.end();
@@ -2585,7 +2959,7 @@ var ProviderHealthCheck = class {
2585
2959
  provider: "mongodb",
2586
2960
  capabilities: {
2587
2961
  collections: collectionNames.length,
2588
- targetCollection: hasCollection ? opts.collection : "NOT FOUND"
2962
+ targetCollection: hasCollection ? opts.collection : "NOT FOUND (will be created on first insert)"
2589
2963
  },
2590
2964
  timestamp
2591
2965
  };
@@ -2598,16 +2972,16 @@ var ProviderHealthCheck = class {
2598
2972
  };
2599
2973
  }
2600
2974
  }
2975
+ /**
2976
+ * Milvus health check — uses baseUrl/uri (matching MilvusProvider constructor).
2977
+ */
2601
2978
  static async checkMilvus(config, timestamp) {
2602
2979
  const opts = config.options;
2603
- const host = opts.host || "localhost";
2604
- const port = opts.port || 19530;
2980
+ const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : "http://localhost:19530");
2605
2981
  try {
2606
2982
  const controller = new AbortController();
2607
2983
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
2608
- const response = await fetch(`http://${host}:${port}/healthz`, {
2609
- signal: controller.signal
2610
- });
2984
+ const response = await fetch(`${baseUrl}/v1/health`, { signal: controller.signal });
2611
2985
  clearTimeout(timeoutId);
2612
2986
  if (!response.ok) {
2613
2987
  throw new Error(`Health check returned ${response.status}`);
@@ -2615,7 +2989,7 @@ var ProviderHealthCheck = class {
2615
2989
  return {
2616
2990
  healthy: true,
2617
2991
  provider: "milvus",
2618
- capabilities: { endpoint: `${host}:${port}` },
2992
+ capabilities: { endpoint: baseUrl },
2619
2993
  timestamp
2620
2994
  };
2621
2995
  } catch (error) {
@@ -2627,14 +3001,18 @@ var ProviderHealthCheck = class {
2627
3001
  };
2628
3002
  }
2629
3003
  }
3004
+ /**
3005
+ * Qdrant health check — uses baseUrl (matching QdrantProvider constructor).
3006
+ */
2630
3007
  static async checkQdrant(config, timestamp) {
2631
3008
  const opts = config.options;
2632
- const baseUrl = opts.baseUrl || opts.url || "http://localhost:6333";
3009
+ const baseUrl = (opts.baseUrl || opts.url || "http://localhost:6333").replace(/\/$/, "");
2633
3010
  try {
2634
- const response = await fetch(`${baseUrl}/health`);
2635
- if (!response.ok) {
2636
- throw new Error(`Health check returned ${response.status}`);
2637
- }
3011
+ const apiKey = opts.apiKey;
3012
+ const response = await fetch(`${baseUrl}/`, {
3013
+ headers: apiKey ? { "api-key": apiKey } : {}
3014
+ });
3015
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2638
3016
  const health = await response.json();
2639
3017
  return {
2640
3018
  healthy: true,
@@ -2651,19 +3029,19 @@ var ProviderHealthCheck = class {
2651
3029
  };
2652
3030
  }
2653
3031
  }
3032
+ /**
3033
+ * ChromaDB health check — uses baseUrl/host (matching ChromaDBProvider constructor).
3034
+ */
2654
3035
  static async checkChromaDB(config, timestamp) {
2655
3036
  const opts = config.options;
2656
- const host = opts.host || "localhost";
2657
- const port = opts.port || 8e3;
3037
+ const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : "http://localhost:8000");
2658
3038
  try {
2659
- const response = await fetch(`http://${host}:${port}/api/v1/heartbeat`);
2660
- if (!response.ok) {
2661
- throw new Error(`Health check returned ${response.status}`);
2662
- }
3039
+ const response = await fetch(`${baseUrl}/api/v1/heartbeat`);
3040
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2663
3041
  return {
2664
3042
  healthy: true,
2665
3043
  provider: "chromadb",
2666
- capabilities: { endpoint: `${host}:${port}` },
3044
+ capabilities: { endpoint: baseUrl },
2667
3045
  timestamp
2668
3046
  };
2669
3047
  } catch (error) {
@@ -2675,38 +3053,43 @@ var ProviderHealthCheck = class {
2675
3053
  };
2676
3054
  }
2677
3055
  }
3056
+ /**
3057
+ * Redis health check — Redis is TCP-only (no HTTP endpoint).
3058
+ * We report healthy=true with a note; actual connectivity is validated at first operation.
3059
+ */
2678
3060
  static async checkRedis(config, timestamp) {
2679
3061
  const opts = config.options;
2680
- const url = opts.url || `redis://${opts.host}:${opts.port}`;
2681
- try {
2682
- await fetch(url);
2683
- return {
2684
- healthy: true,
2685
- provider: "redis",
2686
- capabilities: { endpoint: url },
2687
- timestamp
2688
- };
2689
- } catch (error) {
2690
- return {
2691
- healthy: false,
2692
- provider: "redis",
2693
- error: `Connection check failed: ${error instanceof Error ? error.message : String(error)}. Ensure Redis is running at ${url}`,
2694
- timestamp
2695
- };
3062
+ const url = opts.baseUrl || opts.url || (opts.host && opts.port ? `redis://${opts.host}:${opts.port}` : "redis://localhost:6379");
3063
+ if (url.startsWith("http")) {
3064
+ try {
3065
+ await fetch(url);
3066
+ return { healthy: true, provider: "redis", capabilities: { endpoint: url }, timestamp };
3067
+ } catch (e) {
3068
+ }
2696
3069
  }
3070
+ return {
3071
+ healthy: true,
3072
+ provider: "redis",
3073
+ capabilities: {
3074
+ endpoint: url,
3075
+ note: "Redis uses TCP; connectivity is validated on first operation."
3076
+ },
3077
+ timestamp
3078
+ };
2697
3079
  }
3080
+ /**
3081
+ * Weaviate health check — uses baseUrl/url (matching WeaviateProvider constructor).
3082
+ */
2698
3083
  static async checkWeaviate(config, timestamp) {
2699
3084
  const opts = config.options;
2700
- const url = (opts.url || "http://localhost:8080").replace(/\/$/, "");
3085
+ const baseUrl = (opts.baseUrl || opts.url || "http://localhost:8080").replace(/\/$/, "");
2701
3086
  try {
2702
- const response = await fetch(`${url}/.well-known/ready`);
2703
- if (!response.ok) {
2704
- throw new Error(`Health check returned ${response.status}`);
2705
- }
3087
+ const response = await fetch(`${baseUrl}/v1/.well-known/ready`);
3088
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2706
3089
  return {
2707
3090
  healthy: true,
2708
3091
  provider: "weaviate",
2709
- capabilities: { endpoint: url },
3092
+ capabilities: { endpoint: baseUrl },
2710
3093
  timestamp
2711
3094
  };
2712
3095
  } catch (error) {
@@ -2722,12 +3105,7 @@ var ProviderHealthCheck = class {
2722
3105
  const opts = config.options;
2723
3106
  const baseUrl = (opts.baseUrl || "").replace(/\/$/, "");
2724
3107
  if (!baseUrl) {
2725
- return {
2726
- healthy: false,
2727
- provider: "rest",
2728
- error: "baseUrl is required",
2729
- timestamp
2730
- };
3108
+ return { healthy: false, provider: "rest", error: "baseUrl is required", timestamp };
2731
3109
  }
2732
3110
  try {
2733
3111
  const response = await fetch(`${baseUrl}/health`, {
@@ -2790,11 +3168,7 @@ var ProviderHealthCheck = class {
2790
3168
  return {
2791
3169
  healthy: true,
2792
3170
  provider: "openai",
2793
- capabilities: {
2794
- model: config.model,
2795
- available: hasModel,
2796
- totalModels: models.data.length
2797
- },
3171
+ capabilities: { model: config.model, available: hasModel, totalModels: models.data.length },
2798
3172
  timestamp
2799
3173
  };
2800
3174
  } catch (error) {
@@ -2815,12 +3189,7 @@ var ProviderHealthCheck = class {
2815
3189
  max_tokens: 10,
2816
3190
  messages: [{ role: "user", content: "ping" }]
2817
3191
  });
2818
- return {
2819
- healthy: true,
2820
- provider: "anthropic",
2821
- capabilities: { model: config.model },
2822
- timestamp
2823
- };
3192
+ return { healthy: true, provider: "anthropic", capabilities: { model: config.model }, timestamp };
2824
3193
  } catch (error) {
2825
3194
  return {
2826
3195
  healthy: false,
@@ -2834,20 +3203,14 @@ var ProviderHealthCheck = class {
2834
3203
  const baseUrl = (config.baseUrl || "http://localhost:11434").replace(/\/$/, "");
2835
3204
  try {
2836
3205
  const response = await fetch(`${baseUrl}/api/tags`);
2837
- if (!response.ok) {
2838
- throw new Error(`Health check returned ${response.status}`);
2839
- }
3206
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2840
3207
  const data = await response.json();
2841
3208
  const models = data.models || [];
2842
3209
  const hasModel = models.some((m) => m.name === config.model);
2843
3210
  return {
2844
3211
  healthy: true,
2845
3212
  provider: "ollama",
2846
- capabilities: {
2847
- model: config.model,
2848
- available: hasModel,
2849
- totalModels: models.length
2850
- },
3213
+ capabilities: { model: config.model, available: hasModel, totalModels: models.length },
2851
3214
  timestamp
2852
3215
  };
2853
3216
  } catch (error) {
@@ -2864,18 +3227,11 @@ var ProviderHealthCheck = class {
2864
3227
  const baseUrlRaw = config.baseUrl || ((_a = config.options) == null ? void 0 : _a.baseUrl);
2865
3228
  const baseUrl = (typeof baseUrlRaw === "string" ? baseUrlRaw : "").replace(/\/$/, "");
2866
3229
  if (!baseUrl) {
2867
- return {
2868
- healthy: false,
2869
- provider: config.provider,
2870
- error: "baseUrl is required",
2871
- timestamp
2872
- };
3230
+ return { healthy: false, provider: config.provider, error: "baseUrl is required", timestamp };
2873
3231
  }
2874
3232
  try {
2875
3233
  const headers = (_b = config.options) == null ? void 0 : _b.headers;
2876
- const response = await fetch(`${baseUrl}/health`, {
2877
- headers: headers || void 0
2878
- });
3234
+ const response = await fetch(`${baseUrl}/health`, { headers: headers || void 0 });
2879
3235
  return {
2880
3236
  healthy: response.ok,
2881
3237
  provider: config.provider,
@@ -2892,7 +3248,7 @@ var ProviderHealthCheck = class {
2892
3248
  }
2893
3249
  }
2894
3250
  /**
2895
- * Runs comprehensive health checks on all configured providers.
3251
+ * Runs comprehensive health checks on all configured providers in parallel.
2896
3252
  */
2897
3253
  static async checkAll(vectorDbConfig, llmConfig, embeddingConfig) {
2898
3254
  const [vectorDb, llm, embedding] = await Promise.all([
@@ -2969,23 +3325,278 @@ var VectorPlugin = class {
2969
3325
  }
2970
3326
  };
2971
3327
 
2972
- // src/server.ts
2973
- init_BaseVectorProvider();
2974
- init_PineconeProvider();
2975
- init_PostgreSQLProvider();
2976
- init_MongoDBProvider();
2977
- init_MilvusProvider();
2978
- init_QdrantProvider();
2979
- init_ChromaDBProvider();
2980
- init_RedisProvider();
2981
- init_WeaviateProvider();
2982
- init_LLMFactory();
2983
- init_OpenAIProvider();
2984
- init_AnthropicProvider();
2985
- init_OllamaProvider();
2986
-
2987
- // src/handlers/index.ts
2988
- var import_server = require("next/server");
3328
+ // src/config/ConfigBuilder.ts
3329
+ var ConfigBuilder = class {
3330
+ constructor() {
3331
+ this.config = {
3332
+ projectId: "default-project",
3333
+ rag: {
3334
+ chunkSize: 1e3,
3335
+ chunkOverlap: 200,
3336
+ topK: 5
3337
+ }
3338
+ };
3339
+ }
3340
+ /**
3341
+ * Set the project/application ID for namespacing
3342
+ */
3343
+ projectId(id) {
3344
+ this.config.projectId = id;
3345
+ return this;
3346
+ }
3347
+ /**
3348
+ * Configure the vector database provider
3349
+ */
3350
+ vectorDb(provider, options) {
3351
+ var _a;
3352
+ if (provider === "auto") {
3353
+ this.config.vectorDb = this.autoDetectVectorDb();
3354
+ } else {
3355
+ this.config.vectorDb = {
3356
+ provider,
3357
+ indexName: (_a = options == null ? void 0 : options.indexName) != null ? _a : "default",
3358
+ options: __spreadValues({}, options)
3359
+ };
3360
+ }
3361
+ return this;
3362
+ }
3363
+ /**
3364
+ * Configure the LLM provider for chat
3365
+ */
3366
+ llm(provider, model, apiKey, options) {
3367
+ var _a, _b;
3368
+ if (provider === "auto") {
3369
+ this.config.llm = this.autoDetectLLM();
3370
+ } else {
3371
+ this.config.llm = {
3372
+ provider,
3373
+ model: model != null ? model : "default-model",
3374
+ apiKey,
3375
+ systemPrompt: options == null ? void 0 : options.systemPrompt,
3376
+ maxTokens: (_a = options == null ? void 0 : options.maxTokens) != null ? _a : 1024,
3377
+ temperature: (_b = options == null ? void 0 : options.temperature) != null ? _b : 0.7,
3378
+ baseUrl: options == null ? void 0 : options.baseUrl,
3379
+ options
3380
+ };
3381
+ }
3382
+ return this;
3383
+ }
3384
+ /**
3385
+ * Configure the embedding provider
3386
+ */
3387
+ embedding(provider, model, apiKey, options) {
3388
+ if (provider === "auto") {
3389
+ this.config.embedding = this.autoDetectEmbedding();
3390
+ } else {
3391
+ this.config.embedding = {
3392
+ provider,
3393
+ model: model != null ? model : "default-embedding",
3394
+ apiKey,
3395
+ baseUrl: options == null ? void 0 : options.baseUrl,
3396
+ options
3397
+ };
3398
+ }
3399
+ return this;
3400
+ }
3401
+ /**
3402
+ * Set RAG-specific parameters
3403
+ */
3404
+ rag(options) {
3405
+ var _a;
3406
+ this.config.rag = __spreadValues(__spreadValues({}, (_a = this.config.rag) != null ? _a : {}), options);
3407
+ return this;
3408
+ }
3409
+ /**
3410
+ * Set UI/UX parameters
3411
+ */
3412
+ ui(options) {
3413
+ this.config.ui = options;
3414
+ return this;
3415
+ }
3416
+ /**
3417
+ * Build and return the configuration
3418
+ */
3419
+ build() {
3420
+ const finalConfig = this.config;
3421
+ return finalConfig;
3422
+ }
3423
+ /**
3424
+ * Build and return as JSON for serialization
3425
+ */
3426
+ toJSON() {
3427
+ return JSON.stringify(this.build());
3428
+ }
3429
+ // ============================================================================
3430
+ // Private helper methods for auto-detection
3431
+ // ============================================================================
3432
+ autoDetectVectorDb() {
3433
+ if (process.env.PINECONE_API_KEY && process.env.PINECONE_INDEX) {
3434
+ return {
3435
+ provider: "pinecone",
3436
+ indexName: process.env.PINECONE_INDEX,
3437
+ options: { apiKey: process.env.PINECONE_API_KEY }
3438
+ };
3439
+ }
3440
+ if (process.env.QDRANT_URL) {
3441
+ return {
3442
+ provider: "qdrant",
3443
+ indexName: process.env.QDRANT_COLLECTION || "documents",
3444
+ options: {
3445
+ url: process.env.QDRANT_URL,
3446
+ apiKey: process.env.QDRANT_API_KEY
3447
+ }
3448
+ };
3449
+ }
3450
+ if (process.env.DATABASE_URL) {
3451
+ return {
3452
+ provider: "postgresql",
3453
+ indexName: process.env.PG_TABLE || "documents",
3454
+ options: {
3455
+ connectionString: process.env.DATABASE_URL
3456
+ }
3457
+ };
3458
+ }
3459
+ if (process.env.MONGODB_URI) {
3460
+ return {
3461
+ provider: "mongodb",
3462
+ indexName: process.env.MONGODB_COLLECTION || "documents",
3463
+ options: {
3464
+ uri: process.env.MONGODB_URI,
3465
+ database: process.env.MONGODB_DB || "ai_db",
3466
+ collection: process.env.MONGODB_COLLECTION || "documents"
3467
+ }
3468
+ };
3469
+ }
3470
+ if (process.env.REDIS_URL) {
3471
+ return {
3472
+ provider: "redis",
3473
+ indexName: process.env.REDIS_INDEX || "documents",
3474
+ options: {
3475
+ url: process.env.REDIS_URL
3476
+ }
3477
+ };
3478
+ }
3479
+ return {
3480
+ provider: "qdrant",
3481
+ indexName: "documents",
3482
+ options: {
3483
+ url: process.env.QDRANT_URL || "http://localhost:6333"
3484
+ }
3485
+ };
3486
+ }
3487
+ autoDetectLLM() {
3488
+ if (process.env.OPENAI_API_KEY) {
3489
+ return {
3490
+ provider: "openai",
3491
+ model: process.env.OPENAI_MODEL || "gpt-4o-mini",
3492
+ apiKey: process.env.OPENAI_API_KEY,
3493
+ maxTokens: parseInt(process.env.OPENAI_MAX_TOKENS || "1024"),
3494
+ temperature: parseFloat(process.env.OPENAI_TEMPERATURE || "0.7")
3495
+ };
3496
+ }
3497
+ if (process.env.ANTHROPIC_API_KEY) {
3498
+ return {
3499
+ provider: "anthropic",
3500
+ model: process.env.ANTHROPIC_MODEL || "claude-3-haiku-20240307",
3501
+ apiKey: process.env.ANTHROPIC_API_KEY,
3502
+ maxTokens: parseInt(process.env.ANTHROPIC_MAX_TOKENS || "1024"),
3503
+ temperature: parseFloat(process.env.ANTHROPIC_TEMPERATURE || "0.7")
3504
+ };
3505
+ }
3506
+ if (process.env.OLLAMA_BASE_URL) {
3507
+ return {
3508
+ provider: "ollama",
3509
+ model: process.env.OLLAMA_MODEL || "mistral",
3510
+ baseUrl: process.env.OLLAMA_BASE_URL,
3511
+ maxTokens: parseInt(process.env.OLLAMA_MAX_TOKENS || "1024"),
3512
+ temperature: parseFloat(process.env.OLLAMA_TEMPERATURE || "0.7")
3513
+ };
3514
+ }
3515
+ return {
3516
+ provider: "openai",
3517
+ model: "gpt-4o-mini",
3518
+ apiKey: process.env.OPENAI_API_KEY
3519
+ };
3520
+ }
3521
+ autoDetectEmbedding() {
3522
+ if (process.env.EMBEDDING_PROVIDER) {
3523
+ const provider = process.env.EMBEDDING_PROVIDER;
3524
+ return {
3525
+ provider,
3526
+ model: process.env.EMBEDDING_MODEL || "default",
3527
+ apiKey: process.env.EMBEDDING_API_KEY,
3528
+ baseUrl: process.env.EMBEDDING_BASE_URL
3529
+ };
3530
+ }
3531
+ return {
3532
+ provider: "openai",
3533
+ model: "text-embedding-3-small",
3534
+ apiKey: process.env.OPENAI_API_KEY
3535
+ };
3536
+ }
3537
+ };
3538
+ var PRESETS = {
3539
+ /**
3540
+ * OpenAI + Pinecone: Production-ready cloud setup
3541
+ */
3542
+ "openai-pinecone": {
3543
+ vectorDb: "pinecone",
3544
+ llm: "openai",
3545
+ embedding: "openai"
3546
+ },
3547
+ /**
3548
+ * Claude + Qdrant: Open-source vector DB + proprietary LLM
3549
+ */
3550
+ "claude-qdrant": {
3551
+ vectorDb: "qdrant",
3552
+ llm: "anthropic",
3553
+ embedding: "openai"
3554
+ },
3555
+ /**
3556
+ * Local development: Ollama + local Qdrant
3557
+ */
3558
+ "local-dev": {
3559
+ vectorDb: "qdrant",
3560
+ llm: "ollama",
3561
+ embedding: "ollama"
3562
+ },
3563
+ /**
3564
+ * Fully open-source: Ollama LLM + Qdrant vector DB + Ollama embeddings
3565
+ */
3566
+ "fully-open-source": {
3567
+ vectorDb: "qdrant",
3568
+ llm: "ollama",
3569
+ embedding: "ollama"
3570
+ },
3571
+ /**
3572
+ * PostgreSQL stack: pgvector + OpenAI
3573
+ */
3574
+ "postgres-openai": {
3575
+ vectorDb: "postgresql",
3576
+ llm: "openai",
3577
+ embedding: "openai"
3578
+ },
3579
+ /**
3580
+ * Enterprise MongoDB: MongoDB Atlas with OpenAI
3581
+ */
3582
+ "mongodb-openai": {
3583
+ vectorDb: "mongodb",
3584
+ llm: "openai",
3585
+ embedding: "openai"
3586
+ },
3587
+ /**
3588
+ * Redis stack for caching + search
3589
+ */
3590
+ "redis-openai": {
3591
+ vectorDb: "redis",
3592
+ llm: "openai",
3593
+ embedding: "openai"
3594
+ }
3595
+ };
3596
+ function createFromPreset(presetName) {
3597
+ const preset = PRESETS[presetName];
3598
+ return new ConfigBuilder().vectorDb(preset.vectorDb, { apiKey: process.env[`${preset.vectorDb.toUpperCase()}_API_KEY`] }).llm(preset.llm, void 0, process.env[`${preset.llm.toUpperCase()}_API_KEY`]).embedding(preset.embedding, void 0, process.env[`${preset.embedding.toUpperCase()}_API_KEY`]);
3599
+ }
2989
3600
 
2990
3601
  // src/utils/DocumentParser.ts
2991
3602
  var DocumentParser = class {
@@ -3046,7 +3657,20 @@ var DocumentParser = class {
3046
3657
  }
3047
3658
  };
3048
3659
 
3660
+ // src/server.ts
3661
+ init_BaseVectorProvider();
3662
+ init_PineconeProvider();
3663
+ init_PostgreSQLProvider();
3664
+ init_MongoDBProvider();
3665
+ init_MilvusProvider();
3666
+ init_QdrantProvider();
3667
+ init_ChromaDBProvider();
3668
+ init_RedisProvider();
3669
+ init_WeaviateProvider();
3670
+ init_UniversalVectorProvider();
3671
+
3049
3672
  // src/handlers/index.ts
3673
+ var import_server = require("next/server");
3050
3674
  function createChatHandler(config) {
3051
3675
  const plugin = new VectorPlugin(config);
3052
3676
  return async function POST(req) {
@@ -3135,23 +3759,36 @@ function createUploadHandler(config) {
3135
3759
  0 && (module.exports = {
3136
3760
  AnthropicProvider,
3137
3761
  BaseVectorProvider,
3762
+ BatchProcessor,
3138
3763
  ChromaDBProvider,
3764
+ ConfigBuilder,
3139
3765
  ConfigResolver,
3766
+ ConfigValidator,
3140
3767
  DocumentChunker,
3768
+ DocumentParser,
3769
+ EmbeddingStrategy,
3770
+ EmbeddingStrategyResolver,
3141
3771
  LLMFactory,
3772
+ LLM_PROFILES,
3142
3773
  MilvusProvider,
3143
3774
  MongoDBProvider,
3144
3775
  OllamaProvider,
3145
3776
  OpenAIProvider,
3777
+ PRESETS,
3146
3778
  PineconeProvider,
3147
3779
  Pipeline,
3148
3780
  PostgreSQLProvider,
3781
+ ProviderHealthCheck,
3149
3782
  ProviderRegistry,
3150
3783
  QdrantProvider,
3151
3784
  RedisProvider,
3785
+ UniversalLLMAdapter,
3786
+ UniversalVectorProvider,
3787
+ VECTOR_PROFILES,
3152
3788
  VectorPlugin,
3153
3789
  WeaviateProvider,
3154
3790
  createChatHandler,
3791
+ createFromPreset,
3155
3792
  createHealthHandler,
3156
3793
  createIngestHandler,
3157
3794
  createUploadHandler,