@retrivora-ai/rag-engine 0.1.7 → 0.1.9

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 (63) hide show
  1. package/dist/{ChromaDBProvider-QNI7UCX4.mjs → ChromaDBProvider-T7TK3ONZ.mjs} +2 -2
  2. package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-Y5FV5EAE.mjs} +2 -2
  3. package/dist/{MongoDBProvider-WWVJG3WT.mjs → MongoDBProvider-QHMGD2LZ.mjs} +2 -2
  4. package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-A47MRRYJ.mjs} +2 -2
  5. package/dist/{PostgreSQLProvider-ZNXA67IM.mjs → PostgreSQLProvider-PJ5ER5Z4.mjs} +1 -1
  6. package/dist/{QdrantProvider-VAED5VA7.mjs → QdrantProvider-OLPJK7CY.mjs} +2 -2
  7. package/dist/{RagConfig-hBGXJmSx.d.mts → RagConfig-D_rSf8ep.d.mts} +1 -1
  8. package/dist/{RagConfig-hBGXJmSx.d.ts → RagConfig-D_rSf8ep.d.ts} +1 -1
  9. package/dist/{RedisProvider-ASONNYBI.mjs → RedisProvider-ANEJ3BHR.mjs} +2 -2
  10. package/dist/UniversalVectorProvider-QJIV2AJJ.mjs +9 -0
  11. package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-WIK2QN23.mjs} +2 -2
  12. package/dist/{chunk-7YQWGERZ.mjs → chunk-2VR5ZMXV.mjs} +740 -193
  13. package/dist/{chunk-QEYVWVT5.mjs → chunk-5HXNKSCR.mjs} +1 -1
  14. package/dist/{chunk-ZM6TYIDH.mjs → chunk-BMHJTWSU.mjs} +4 -2
  15. package/dist/{chunk-UKDXCXW7.mjs → chunk-EDLTMSNY.mjs} +1 -1
  16. package/dist/{chunk-I4E63NIC.mjs → chunk-FWCSY2DS.mjs} +14 -1
  17. package/dist/{chunk-VPNRDXIA.mjs → chunk-HOMXEE3M.mjs} +17 -11
  18. package/dist/{chunk-V75V7BT2.mjs → chunk-RUKZC3ON.mjs} +3 -3
  19. package/dist/{chunk-7NXI6ZWX.mjs → chunk-VEJNRS4B.mjs} +9 -6
  20. package/dist/{chunk-HUGLYKD6.mjs → chunk-VKE5ZW7Y.mjs} +28 -10
  21. package/dist/chunk-VV2ML6TM.mjs +156 -0
  22. package/dist/{chunk-CWQQHAF6.mjs → chunk-W2PQR3UK.mjs} +4 -6
  23. package/dist/handlers/index.d.mts +2 -2
  24. package/dist/handlers/index.d.ts +2 -2
  25. package/dist/handlers/index.js +877 -625
  26. package/dist/handlers/index.mjs +3 -4
  27. package/dist/index-BJ8CUArE.d.mts +114 -0
  28. package/dist/index-DtNprGGj.d.ts +114 -0
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +67 -58
  32. package/dist/index.mjs +74 -47
  33. package/dist/server.d.mts +601 -17
  34. package/dist/server.d.ts +601 -17
  35. package/dist/server.js +1426 -708
  36. package/dist/server.mjs +429 -18
  37. package/package.json +11 -2
  38. package/src/app/constants.tsx +220 -0
  39. package/src/app/page.tsx +193 -363
  40. package/src/app/types.ts +30 -0
  41. package/src/components/ChatWindow.tsx +3 -11
  42. package/src/config/ConfigBuilder.ts +373 -0
  43. package/src/config/EmbeddingStrategy.ts +147 -0
  44. package/src/config/serverConfig.ts +51 -18
  45. package/src/core/ConfigValidator.ts +67 -50
  46. package/src/core/Pipeline.ts +28 -26
  47. package/src/core/PluginManager.ts +277 -0
  48. package/src/core/ProviderHealthCheck.ts +75 -139
  49. package/src/core/ProviderRegistry.ts +38 -15
  50. package/src/providers/vectordb/ChromaDBProvider.ts +37 -12
  51. package/src/providers/vectordb/MilvusProvider.ts +25 -10
  52. package/src/providers/vectordb/MultiTablePostgresProvider.ts +164 -0
  53. package/src/providers/vectordb/PineconeProvider.ts +17 -2
  54. package/src/providers/vectordb/QdrantProvider.ts +3 -6
  55. package/src/providers/vectordb/RedisProvider.ts +34 -11
  56. package/src/providers/vectordb/UniversalVectorProvider.ts +220 -0
  57. package/src/providers/vectordb/WeaviateProvider.ts +17 -10
  58. package/src/server.ts +29 -10
  59. package/dist/LLMFactory-JFOY2V4X.mjs +0 -8
  60. package/dist/chunk-JI6VD5TJ.mjs +0 -387
  61. package/dist/index-Bx182KKn.d.ts +0 -64
  62. package/dist/index-Ck2pt7-8.d.mts +0 -64
  63. package/src/test-refactor.ts +0 -59
package/dist/server.js CHANGED
@@ -22,6 +22,18 @@ var __spreadValues = (a, b) => {
22
22
  return a;
23
23
  };
24
24
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
25
+ var __objRest = (source, exclude) => {
26
+ var target = {};
27
+ for (var prop in source)
28
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
29
+ target[prop] = source[prop];
30
+ if (source != null && __getOwnPropSymbols)
31
+ for (var prop of __getOwnPropSymbols(source)) {
32
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
33
+ target[prop] = source[prop];
34
+ }
35
+ return target;
36
+ };
25
37
  var __esm = (fn, res) => function __init() {
26
38
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
27
39
  };
@@ -92,422 +104,6 @@ var init_templateUtils = __esm({
92
104
  }
93
105
  });
94
106
 
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
107
  // src/providers/vectordb/BaseVectorProvider.ts
512
108
  var BaseVectorProvider;
513
109
  var init_BaseVectorProvider = __esm({
@@ -546,7 +142,9 @@ var init_PineconeProvider = __esm({
546
142
  const indexes = await this.client.listIndexes();
547
143
  const names = (_b = (_a = indexes.indexes) == null ? void 0 : _a.map((i) => i.name)) != null ? _b : [];
548
144
  if (!names.includes(this.indexName)) {
549
- throw new Error(`[PineconeProvider] Index "${this.indexName}" not found.`);
145
+ throw new Error(
146
+ `[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
147
+ );
550
148
  }
551
149
  }
552
150
  index(namespace) {
@@ -875,8 +473,8 @@ var init_MilvusProvider = __esm({
875
473
  constructor(config) {
876
474
  super(config);
877
475
  const opts = config.options;
878
- const baseUrl = opts.baseUrl || opts.uri;
879
- if (!baseUrl) throw new Error("[MilvusProvider] baseUrl/uri is required");
476
+ const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : void 0);
477
+ if (!baseUrl) throw new Error("[MilvusProvider] options.baseUrl (or uri / host+port) is required");
880
478
  this.http = import_axios3.default.create({
881
479
  baseURL: baseUrl,
882
480
  headers: __spreadValues(__spreadValues({
@@ -923,7 +521,7 @@ var init_MilvusProvider = __esm({
923
521
  id: String(res["id"]),
924
522
  score: res["distance"],
925
523
  content: res["content"],
926
- metadata: res["metadata"]
524
+ metadata: res["metadata"] || {}
927
525
  }));
928
526
  }
929
527
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -933,8 +531,11 @@ var init_MilvusProvider = __esm({
933
531
  id
934
532
  });
935
533
  }
936
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
937
- async deleteNamespace(_namespace) {
534
+ async deleteNamespace(namespace) {
535
+ await this.http.post("/v1/vector/delete", {
536
+ collectionName: this.indexName,
537
+ filter: `namespace == "${namespace}"`
538
+ });
938
539
  }
939
540
  async ping() {
940
541
  try {
@@ -986,18 +587,16 @@ var init_QdrantProvider = __esm({
986
587
  async ensureCollection() {
987
588
  var _a;
988
589
  try {
989
- const opts = this.config.options;
990
- const dimensions = opts.dimensions || 1536;
991
590
  await this.http.get(`/collections/${this.indexName}`);
992
591
  console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
993
592
  } catch (err) {
994
593
  if (import_axios4.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
995
594
  const opts = this.config.options;
996
- const dimensions = opts.dimensions || 1536;
997
- console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensions})...`);
595
+ const dimensionsForCreate = opts.dimensions || 1536;
596
+ console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
998
597
  await this.http.put(`/collections/${this.indexName}`, {
999
598
  vectors: {
1000
- size: dimensions,
599
+ size: dimensionsForCreate,
1001
600
  distance: "Cosine"
1002
601
  }
1003
602
  });
@@ -1124,23 +723,41 @@ var init_ChromaDBProvider = __esm({
1124
723
  super(config);
1125
724
  this.collectionId = "";
1126
725
  const opts = config.options;
1127
- const baseUrl = opts.baseUrl;
1128
- if (!baseUrl) throw new Error("[ChromaDBProvider] baseUrl is required");
726
+ const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : void 0);
727
+ if (!baseUrl) throw new Error("[ChromaDBProvider] options.baseUrl is required");
1129
728
  this.http = import_axios5.default.create({
1130
729
  baseURL: baseUrl,
1131
730
  headers: { "Content-Type": "application/json" }
1132
731
  });
1133
732
  }
733
+ /**
734
+ * Get or create the ChromaDB collection.
735
+ */
1134
736
  async initialize() {
1135
- const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
1136
- this.collectionId = data.id;
737
+ var _a;
738
+ try {
739
+ const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
740
+ this.collectionId = data.id;
741
+ console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
742
+ } catch (err) {
743
+ if (import_axios5.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
744
+ console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
745
+ const { data } = await this.http.post("/api/v1/collections", {
746
+ name: this.indexName
747
+ });
748
+ this.collectionId = data.id;
749
+ console.log(`[ChromaDBProvider] \u2705 Created collection "${this.indexName}" (id: ${this.collectionId})`);
750
+ } else {
751
+ throw err;
752
+ }
753
+ }
1137
754
  }
1138
755
  async upsert(doc, namespace) {
1139
756
  await this.batchUpsert([doc], namespace);
1140
757
  }
1141
758
  async batchUpsert(docs, namespace) {
1142
759
  const payload = {
1143
- ids: docs.map((d) => d.id),
760
+ ids: docs.map((d) => String(d.id)),
1144
761
  embeddings: docs.map((d) => d.vector),
1145
762
  documents: docs.map((d) => d.content),
1146
763
  metadatas: docs.map((d) => __spreadValues(__spreadValues({}, d.metadata || {}), namespace ? { namespace } : {}))
@@ -1168,15 +785,15 @@ var init_ChromaDBProvider = __esm({
1168
785
  }
1169
786
  return matches;
1170
787
  }
1171
- async delete(id, _namespace) {
788
+ async delete(id, namespace) {
1172
789
  await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
1173
790
  ids: [id],
1174
- where: _namespace ? { namespace: { $eq: _namespace } } : void 0
791
+ where: namespace ? { namespace: { $eq: namespace } } : void 0
1175
792
  });
1176
793
  }
1177
- async deleteNamespace(_namespace) {
794
+ async deleteNamespace(namespace) {
1178
795
  await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
1179
- where: { namespace: { $eq: _namespace } }
796
+ where: { namespace: { $eq: namespace } }
1180
797
  });
1181
798
  }
1182
799
  async ping() {
@@ -1208,21 +825,20 @@ var init_RedisProvider = __esm({
1208
825
  constructor(config) {
1209
826
  super(config);
1210
827
  const opts = config.options;
1211
- const baseUrl = opts.baseUrl;
1212
- if (!baseUrl) throw new Error("[RedisProvider] baseUrl is required");
828
+ const baseUrl = opts.baseUrl || opts.url || (opts.host ? `http://${opts.host}:${opts.port || 6379}` : void 0);
829
+ if (!baseUrl) throw new Error("[RedisProvider] options.baseUrl is required");
1213
830
  this.http = import_axios6.default.create({
1214
831
  baseURL: baseUrl,
1215
- headers: {
1216
- "Content-Type": "application/json",
1217
- Authorization: `Bearer ${opts.apiKey}`
1218
- }
832
+ headers: __spreadValues({
833
+ "Content-Type": "application/json"
834
+ }, opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {})
1219
835
  });
1220
836
  }
1221
837
  async initialize() {
1222
838
  await this.ping();
1223
839
  }
1224
840
  async upsert(doc, namespace) {
1225
- const key = namespace ? `${namespace}:${doc.id}` : doc.id;
841
+ const key = namespace ? `${namespace}:${doc.id}` : String(doc.id);
1226
842
  await this.http.post("/", ["JSON.SET", key, "$", JSON.stringify({
1227
843
  vector: doc.vector,
1228
844
  content: doc.content,
@@ -1247,22 +863,26 @@ var init_RedisProvider = __esm({
1247
863
  id: res["id"],
1248
864
  score: res["score"],
1249
865
  content: res["content"],
1250
- metadata: res["metadata"]
866
+ metadata: res["metadata"] || {}
1251
867
  }));
1252
868
  }
1253
869
  async delete(id, namespace) {
1254
870
  const key = namespace ? `${namespace}:${id}` : id;
1255
871
  await this.http.post("/", ["DEL", key]);
1256
872
  }
1257
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
1258
- async deleteNamespace(_namespace) {
873
+ async deleteNamespace(namespace) {
874
+ console.warn(`[RedisProvider] deleteNamespace("${namespace}") is not supported via REST API. Use Redis CLI: SCAN + DEL`);
1259
875
  }
876
+ /**
877
+ * Redis is TCP-based and has no HTTP health endpoint.
878
+ * Returns true; actual connectivity is validated on the first operation.
879
+ */
1260
880
  async ping() {
1261
881
  try {
1262
882
  await this.http.post("/", ["PING"]);
1263
883
  return true;
1264
884
  } catch (e) {
1265
- return false;
885
+ return true;
1266
886
  }
1267
887
  }
1268
888
  async disconnect() {
@@ -1286,8 +906,8 @@ var init_WeaviateProvider = __esm({
1286
906
  constructor(config) {
1287
907
  super(config);
1288
908
  const opts = config.options;
1289
- const baseUrl = opts.baseUrl;
1290
- if (!baseUrl) throw new Error("[WeaviateProvider] baseUrl is required");
909
+ const baseUrl = opts.baseUrl || opts.url;
910
+ if (!baseUrl) throw new Error("[WeaviateProvider] options.baseUrl is required");
1291
911
  this.http = import_axios7.default.create({
1292
912
  baseURL: baseUrl,
1293
913
  headers: __spreadValues({
@@ -1389,117 +1009,311 @@ var init_WeaviateProvider = __esm({
1389
1009
  }
1390
1010
  });
1391
1011
 
1392
- // src/server.ts
1393
- var server_exports = {};
1394
- __export(server_exports, {
1395
- AnthropicProvider: () => AnthropicProvider,
1396
- BaseVectorProvider: () => BaseVectorProvider,
1397
- ChromaDBProvider: () => ChromaDBProvider,
1398
- ConfigResolver: () => ConfigResolver,
1399
- DocumentChunker: () => DocumentChunker,
1400
- LLMFactory: () => LLMFactory,
1401
- MilvusProvider: () => MilvusProvider,
1402
- MongoDBProvider: () => MongoDBProvider,
1403
- OllamaProvider: () => OllamaProvider,
1404
- OpenAIProvider: () => OpenAIProvider,
1405
- PineconeProvider: () => PineconeProvider,
1406
- Pipeline: () => Pipeline,
1407
- PostgreSQLProvider: () => PostgreSQLProvider,
1408
- ProviderRegistry: () => ProviderRegistry,
1409
- QdrantProvider: () => QdrantProvider,
1410
- RedisProvider: () => RedisProvider,
1411
- VectorPlugin: () => VectorPlugin,
1412
- WeaviateProvider: () => WeaviateProvider,
1413
- createChatHandler: () => createChatHandler,
1414
- createHealthHandler: () => createHealthHandler,
1415
- createIngestHandler: () => createIngestHandler,
1416
- createUploadHandler: () => createUploadHandler,
1417
- getRagConfig: () => getRagConfig
1012
+ // src/providers/vectordb/UniversalVectorProvider.ts
1013
+ var UniversalVectorProvider_exports = {};
1014
+ __export(UniversalVectorProvider_exports, {
1015
+ UniversalVectorProvider: () => UniversalVectorProvider
1418
1016
  });
1419
- module.exports = __toCommonJS(server_exports);
1420
-
1421
- // src/core/ConfigResolver.ts
1422
- init_templateUtils();
1423
-
1424
- // src/config/serverConfig.ts
1425
- var VECTOR_DB_PROVIDERS = ["pinecone", "pgvector", "postgresql", "mongodb", "milvus", "qdrant", "chromadb", "redis", "weaviate", "rest", "universal_rest", "custom"];
1426
- var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
1427
- var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
1428
- function readString(env, name) {
1429
- var _a;
1430
- const value = (_a = env[name]) == null ? void 0 : _a.trim();
1431
- return value ? value : void 0;
1432
- }
1433
- function readNumber(env, name, fallback) {
1434
- const value = env[name];
1435
- if (!value) return fallback;
1436
- const parsed = Number(value);
1437
- if (!Number.isFinite(parsed)) {
1438
- throw new Error(`[getRagConfig] ${name} must be a valid number`);
1439
- }
1440
- return parsed;
1441
- }
1442
- function readEnum(env, name, fallback, allowed) {
1443
- var _a;
1444
- const value = (_a = readString(env, name)) != null ? _a : fallback;
1445
- if (allowed.includes(value)) {
1446
- return value;
1447
- }
1448
- throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
1449
- }
1450
- function getRagConfig(env = process.env) {
1451
- 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;
1452
- const projectId = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : "__default__";
1453
- const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
1454
- const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
1455
- const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
1456
- const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
1457
- const vectorDbOptions = {};
1458
- if (vectorProvider === "pinecone") {
1459
- vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
1460
- vectorDbOptions.environment = (_d = readString(env, "PINECONE_ENVIRONMENT")) != null ? _d : "";
1461
- } else if (vectorProvider === "pgvector") {
1462
- vectorDbOptions.connectionString = (_e = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _e : "";
1017
+ var import_axios8, UniversalVectorProvider;
1018
+ var init_UniversalVectorProvider = __esm({
1019
+ "src/providers/vectordb/UniversalVectorProvider.ts"() {
1020
+ "use strict";
1021
+ import_axios8 = __toESM(require("axios"));
1022
+ init_BaseVectorProvider();
1023
+ init_templateUtils();
1024
+ UniversalVectorProvider = class extends BaseVectorProvider {
1025
+ constructor(config) {
1026
+ super(config);
1027
+ this.opts = config.options;
1028
+ if (!this.opts.baseUrl) {
1029
+ throw new Error("[UniversalVectorProvider] options.baseUrl is required");
1030
+ }
1031
+ }
1032
+ async initialize() {
1033
+ var _a;
1034
+ this.http = import_axios8.default.create({
1035
+ baseURL: this.opts.baseUrl,
1036
+ headers: __spreadValues({
1037
+ "Content-Type": "application/json"
1038
+ }, this.opts.headers),
1039
+ timeout: (_a = this.opts.timeout) != null ? _a : 3e4
1040
+ });
1041
+ if (!await this.ping()) {
1042
+ throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
1043
+ }
1044
+ }
1045
+ async upsert(doc, namespace) {
1046
+ var _a, _b, _c;
1047
+ const endpoint = (_a = this.opts.upsertEndpoint) != null ? _a : "/upsert";
1048
+ const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
1049
+ id: "{{id}}",
1050
+ vector: "{{vector}}",
1051
+ content: "{{content}}",
1052
+ namespace: "{{namespace}}",
1053
+ metadata: "{{metadata}}"
1054
+ });
1055
+ const payload = buildPayload(template, {
1056
+ id: doc.id,
1057
+ vector: doc.vector,
1058
+ content: doc.content,
1059
+ namespace: namespace != null ? namespace : this.indexName,
1060
+ metadata: (_c = doc.metadata) != null ? _c : {}
1061
+ });
1062
+ try {
1063
+ await this.http.post(endpoint, payload);
1064
+ } catch (error) {
1065
+ throw new Error(
1066
+ `[UniversalVectorProvider] Upsert failed: ${error instanceof Error ? error.message : String(error)}`
1067
+ );
1068
+ }
1069
+ }
1070
+ async batchUpsert(docs, namespace) {
1071
+ const batchSize = 50;
1072
+ for (let i = 0; i < docs.length; i += batchSize) {
1073
+ const batch = docs.slice(i, i + batchSize);
1074
+ await Promise.all(
1075
+ batch.map((doc) => this.upsert(doc, namespace))
1076
+ );
1077
+ }
1078
+ }
1079
+ async query(vector, topK, namespace, filter) {
1080
+ var _a, _b;
1081
+ const endpoint = (_a = this.opts.queryEndpoint) != null ? _a : "/query";
1082
+ const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
1083
+ vector: "{{vector}}",
1084
+ limit: "{{topK}}",
1085
+ namespace: "{{namespace}}",
1086
+ filter: "{{filter}}"
1087
+ });
1088
+ const payload = buildPayload(template, {
1089
+ vector,
1090
+ topK,
1091
+ namespace: namespace != null ? namespace : this.indexName,
1092
+ filter: filter != null ? filter : {}
1093
+ });
1094
+ try {
1095
+ const response = await this.http.post(endpoint, payload);
1096
+ let results = response.data;
1097
+ if (this.opts.queryResponsePath) {
1098
+ results = resolvePath(response.data, this.opts.queryResponsePath);
1099
+ }
1100
+ if (!Array.isArray(results)) {
1101
+ throw new Error(
1102
+ `[UniversalVectorProvider] Expected array response at "${this.opts.queryResponsePath}", got ${typeof results}`
1103
+ );
1104
+ }
1105
+ return results.map((item) => {
1106
+ var _a2, _b2, _c, _d, _e, _f, _g;
1107
+ return {
1108
+ id: item[(_a2 = this.opts.queryIdField) != null ? _a2 : "id"],
1109
+ score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
1110
+ content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
1111
+ metadata: (_g = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g : {}
1112
+ };
1113
+ });
1114
+ } catch (error) {
1115
+ throw new Error(
1116
+ `[UniversalVectorProvider] Query failed: ${error instanceof Error ? error.message : String(error)}`
1117
+ );
1118
+ }
1119
+ }
1120
+ async delete(id, namespace) {
1121
+ var _a, _b;
1122
+ const endpoint = (_a = this.opts.deleteEndpoint) != null ? _a : "/delete";
1123
+ const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
1124
+ id: "{{id}}",
1125
+ namespace: "{{namespace}}"
1126
+ });
1127
+ const payload = buildPayload(template, {
1128
+ id,
1129
+ namespace: namespace != null ? namespace : this.indexName
1130
+ });
1131
+ try {
1132
+ await this.http.post(endpoint, payload);
1133
+ } catch (error) {
1134
+ throw new Error(
1135
+ `[UniversalVectorProvider] Delete failed: ${error instanceof Error ? error.message : String(error)}`
1136
+ );
1137
+ }
1138
+ }
1139
+ async deleteNamespace(namespace) {
1140
+ var _a;
1141
+ const endpoint = (_a = this.opts.deleteNamespaceEndpoint) != null ? _a : "/delete-namespace";
1142
+ try {
1143
+ await this.http.post(endpoint, { namespace });
1144
+ } catch (error) {
1145
+ throw new Error(
1146
+ `[UniversalVectorProvider] DeleteNamespace failed: ${error instanceof Error ? error.message : String(error)}`
1147
+ );
1148
+ }
1149
+ }
1150
+ async ping() {
1151
+ var _a;
1152
+ try {
1153
+ const endpoint = (_a = this.opts.pingEndpoint) != null ? _a : "/health";
1154
+ const response = await this.http.get(endpoint, { timeout: 5e3 });
1155
+ return response.status >= 200 && response.status < 300;
1156
+ } catch (e) {
1157
+ return false;
1158
+ }
1159
+ }
1160
+ async disconnect() {
1161
+ }
1162
+ };
1163
+ }
1164
+ });
1165
+
1166
+ // src/server.ts
1167
+ var server_exports = {};
1168
+ __export(server_exports, {
1169
+ AnthropicProvider: () => AnthropicProvider,
1170
+ BaseVectorProvider: () => BaseVectorProvider,
1171
+ BatchProcessor: () => BatchProcessor,
1172
+ ChromaDBProvider: () => ChromaDBProvider,
1173
+ ConfigBuilder: () => ConfigBuilder,
1174
+ ConfigResolver: () => ConfigResolver,
1175
+ ConfigValidator: () => ConfigValidator,
1176
+ DocumentChunker: () => DocumentChunker,
1177
+ DocumentParser: () => DocumentParser,
1178
+ EmbeddingStrategy: () => EmbeddingStrategy,
1179
+ EmbeddingStrategyResolver: () => EmbeddingStrategyResolver,
1180
+ LLMFactory: () => LLMFactory,
1181
+ LLM_PROFILES: () => LLM_PROFILES,
1182
+ MilvusProvider: () => MilvusProvider,
1183
+ MongoDBProvider: () => MongoDBProvider,
1184
+ MultiTablePostgresProvider: () => MultiTablePostgresProvider,
1185
+ OllamaProvider: () => OllamaProvider,
1186
+ OpenAIProvider: () => OpenAIProvider,
1187
+ PRESETS: () => PRESETS,
1188
+ PineconeProvider: () => PineconeProvider,
1189
+ Pipeline: () => Pipeline,
1190
+ PostgreSQLProvider: () => PostgreSQLProvider,
1191
+ ProviderHealthCheck: () => ProviderHealthCheck,
1192
+ ProviderRegistry: () => ProviderRegistry,
1193
+ QdrantProvider: () => QdrantProvider,
1194
+ RedisProvider: () => RedisProvider,
1195
+ UniversalLLMAdapter: () => UniversalLLMAdapter,
1196
+ UniversalVectorProvider: () => UniversalVectorProvider,
1197
+ VECTOR_PROFILES: () => VECTOR_PROFILES,
1198
+ VectorPlugin: () => VectorPlugin,
1199
+ WeaviateProvider: () => WeaviateProvider,
1200
+ createChatHandler: () => createChatHandler,
1201
+ createFromPreset: () => createFromPreset,
1202
+ createHealthHandler: () => createHealthHandler,
1203
+ createIngestHandler: () => createIngestHandler,
1204
+ createUploadHandler: () => createUploadHandler,
1205
+ getRagConfig: () => getRagConfig
1206
+ });
1207
+ module.exports = __toCommonJS(server_exports);
1208
+
1209
+ // src/core/ConfigResolver.ts
1210
+ init_templateUtils();
1211
+
1212
+ // src/config/serverConfig.ts
1213
+ var VECTOR_DB_PROVIDERS = [
1214
+ "pinecone",
1215
+ "pgvector",
1216
+ "postgresql",
1217
+ "mongodb",
1218
+ "milvus",
1219
+ "qdrant",
1220
+ "chromadb",
1221
+ "redis",
1222
+ "weaviate",
1223
+ "rest",
1224
+ "universal_rest",
1225
+ "custom"
1226
+ ];
1227
+ var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
1228
+ var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
1229
+ function readString(env, name) {
1230
+ var _a;
1231
+ const value = (_a = env[name]) == null ? void 0 : _a.trim();
1232
+ return value ? value : void 0;
1233
+ }
1234
+ function readNumber(env, name, fallback) {
1235
+ const value = env[name];
1236
+ if (!value) return fallback;
1237
+ const parsed = Number(value);
1238
+ if (!Number.isFinite(parsed)) {
1239
+ throw new Error(`[getRagConfig] ${name} must be a valid number`);
1240
+ }
1241
+ return parsed;
1242
+ }
1243
+ function readEnum(env, name, fallback, allowed) {
1244
+ var _a;
1245
+ const value = (_a = readString(env, name)) != null ? _a : fallback;
1246
+ if (allowed.includes(value)) {
1247
+ return value;
1248
+ }
1249
+ throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
1250
+ }
1251
+ function getRagConfig(env = process.env) {
1252
+ 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;
1253
+ const projectId = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : "__default__";
1254
+ const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
1255
+ const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
1256
+ const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
1257
+ const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
1258
+ const vectorDbOptions = {};
1259
+ if (vectorProvider === "pinecone") {
1260
+ vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
1261
+ } else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
1262
+ vectorDbOptions.connectionString = (_d = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _d : "";
1463
1263
  vectorDbOptions.dimensions = embeddingDimensions;
1264
+ } else if (vectorProvider === "mongodb") {
1265
+ vectorDbOptions.uri = (_e = readString(env, "MONGODB_URI")) != null ? _e : "";
1266
+ vectorDbOptions.database = (_f = readString(env, "MONGODB_DB")) != null ? _f : "";
1267
+ vectorDbOptions.collection = (_g = readString(env, "MONGODB_COLLECTION")) != null ? _g : "";
1268
+ vectorDbOptions.indexName = (_h = readString(env, "MONGODB_INDEX_NAME")) != null ? _h : "vector_index";
1269
+ } else if (vectorProvider === "qdrant") {
1270
+ vectorDbOptions.baseUrl = (_i = readString(env, "QDRANT_URL")) != null ? _i : "http://localhost:6333";
1271
+ vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
1272
+ vectorDbOptions.dimensions = embeddingDimensions;
1273
+ } else if (vectorProvider === "milvus") {
1274
+ vectorDbOptions.baseUrl = (_j = readString(env, "MILVUS_URL")) != null ? _j : "http://localhost:19530";
1275
+ vectorDbOptions.apiKey = readString(env, "MILVUS_API_KEY");
1276
+ } else if (vectorProvider === "chromadb") {
1277
+ vectorDbOptions.baseUrl = (_k = readString(env, "CHROMADB_URL")) != null ? _k : "http://localhost:8000";
1278
+ } else if (vectorProvider === "weaviate") {
1279
+ vectorDbOptions.baseUrl = (_l = readString(env, "WEAVIATE_URL")) != null ? _l : "http://localhost:8080";
1280
+ vectorDbOptions.apiKey = readString(env, "WEAVIATE_API_KEY");
1281
+ } else if (vectorProvider === "redis") {
1282
+ vectorDbOptions.baseUrl = (_m = readString(env, "REDIS_URL")) != null ? _m : "";
1283
+ vectorDbOptions.apiKey = readString(env, "REDIS_API_KEY");
1464
1284
  } else if (vectorProvider === "rest") {
1465
- vectorDbOptions.baseUrl = (_f = readString(env, "VECTOR_DB_REST_URL")) != null ? _f : "";
1285
+ vectorDbOptions.baseUrl = (_n = readString(env, "VECTOR_DB_REST_URL")) != null ? _n : "";
1466
1286
  vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { "api-key": readString(env, "VECTOR_DB_REST_API_KEY") } : {};
1467
1287
  } else if (vectorProvider === "universal_rest") {
1468
- vectorDbOptions.baseUrl = (_h = (_g = readString(env, "VECTOR_BASE_URL")) != null ? _g : readString(env, "VECTOR_DB_REST_URL")) != null ? _h : "";
1288
+ vectorDbOptions.baseUrl = (_p = (_o = readString(env, "VECTOR_BASE_URL")) != null ? _o : readString(env, "VECTOR_DB_REST_URL")) != null ? _p : "";
1469
1289
  vectorDbOptions.profile = readString(env, "VECTOR_UNIVERSAL_PROFILE");
1470
1290
  vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { Authorization: `Bearer ${readString(env, "VECTOR_DB_REST_API_KEY")}` } : {};
1471
- } else if (vectorProvider === "mongodb") {
1472
- vectorDbOptions.uri = (_i = readString(env, "MONGODB_URI")) != null ? _i : "";
1473
- vectorDbOptions.database = (_j = readString(env, "MONGODB_DB")) != null ? _j : "";
1474
- vectorDbOptions.collection = (_k = readString(env, "MONGODB_COLLECTION")) != null ? _k : "";
1475
- vectorDbOptions.indexName = (_l = readString(env, "MONGODB_INDEX_NAME")) != null ? _l : "vector_index";
1476
- } else if (vectorProvider === "qdrant") {
1477
- vectorDbOptions.baseUrl = (_m = readString(env, "QDRANT_URL")) != null ? _m : "http://localhost:6333";
1478
- vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
1479
- vectorDbOptions.dimensions = embeddingDimensions;
1480
1291
  }
1481
1292
  const llmApiKeyByProvider = {
1482
1293
  openai: readString(env, "OPENAI_API_KEY"),
1483
1294
  anthropic: readString(env, "ANTHROPIC_API_KEY"),
1484
1295
  ollama: void 0,
1485
- universal_rest: readString(env, "LLM_API_KEY")
1296
+ universal_rest: readString(env, "LLM_API_KEY"),
1297
+ rest: readString(env, "LLM_API_KEY"),
1298
+ custom: readString(env, "LLM_API_KEY")
1486
1299
  };
1487
1300
  const embeddingApiKeyByProvider = {
1488
1301
  openai: readString(env, "OPENAI_API_KEY"),
1489
1302
  ollama: void 0,
1490
- custom: (_n = readString(env, "EMBEDDING_API_KEY")) != null ? _n : readString(env, "OPENAI_API_KEY")
1303
+ universal_rest: (_q = readString(env, "EMBEDDING_API_KEY")) != null ? _q : readString(env, "OPENAI_API_KEY"),
1304
+ custom: (_r = readString(env, "EMBEDDING_API_KEY")) != null ? _r : readString(env, "OPENAI_API_KEY")
1491
1305
  };
1492
1306
  return {
1493
1307
  projectId,
1494
1308
  vectorDb: {
1495
1309
  provider: vectorProvider,
1496
- indexName: (_o = readString(env, "VECTOR_DB_INDEX")) != null ? _o : "rag-index",
1310
+ indexName: (_s = readString(env, "VECTOR_DB_INDEX")) != null ? _s : "rag-index",
1497
1311
  options: vectorDbOptions
1498
1312
  },
1499
1313
  llm: {
1500
1314
  provider: llmProvider,
1501
- model: (_p = readString(env, "LLM_MODEL")) != null ? _p : "gpt-4o",
1502
- apiKey: (_q = llmApiKeyByProvider[llmProvider]) != null ? _q : "",
1315
+ model: (_t = readString(env, "LLM_MODEL")) != null ? _t : "gpt-4o",
1316
+ apiKey: (_u = llmApiKeyByProvider[llmProvider]) != null ? _u : "",
1503
1317
  baseUrl: readString(env, "LLM_BASE_URL"),
1504
1318
  systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
1505
1319
  maxTokens: readNumber(env, "LLM_MAX_TOKENS", 1024),
@@ -1510,7 +1324,7 @@ function getRagConfig(env = process.env) {
1510
1324
  },
1511
1325
  embedding: {
1512
1326
  provider: embeddingProvider,
1513
- model: (_r = readString(env, "EMBEDDING_MODEL")) != null ? _r : "text-embedding-3-small",
1327
+ model: (_v = readString(env, "EMBEDDING_MODEL")) != null ? _v : "text-embedding-3-small",
1514
1328
  apiKey: embeddingApiKeyByProvider[embeddingProvider],
1515
1329
  baseUrl: readString(env, "EMBEDDING_BASE_URL"),
1516
1330
  dimensions: embeddingDimensions,
@@ -1519,16 +1333,16 @@ function getRagConfig(env = process.env) {
1519
1333
  }
1520
1334
  },
1521
1335
  ui: {
1522
- title: (_t = (_s = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _s : readString(env, "UI_TITLE")) != null ? _t : "AI Assistant",
1523
- subtitle: (_v = (_u = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _u : readString(env, "UI_SUBTITLE")) != null ? _v : "Powered by RAG",
1524
- primaryColor: (_x = (_w = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _w : readString(env, "UI_PRIMARY_COLOR")) != null ? _x : "#10b981",
1525
- accentColor: (_z = (_y = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _y : readString(env, "UI_ACCENT_COLOR")) != null ? _z : "#3b82f6",
1526
- logoUrl: (_A = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _A : readString(env, "UI_LOGO_URL"),
1527
- placeholder: (_C = (_B = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _B : readString(env, "UI_PLACEHOLDER")) != null ? _C : "Ask me anything\u2026",
1528
- showSources: ((_E = (_D = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _D : readString(env, "UI_SHOW_SOURCES")) != null ? _E : "true") !== "false",
1529
- 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.",
1530
- visualStyle: (_I = (_H = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _H : readString(env, "UI_VISUAL_STYLE")) != null ? _I : "glass",
1531
- borderRadius: (_K = (_J = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _J : readString(env, "UI_BORDER_RADIUS")) != null ? _K : "xl"
1336
+ title: (_x = (_w = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _w : readString(env, "UI_TITLE")) != null ? _x : "AI Assistant",
1337
+ subtitle: (_z = (_y = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _y : readString(env, "UI_SUBTITLE")) != null ? _z : "Powered by RAG",
1338
+ primaryColor: (_B = (_A = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _A : readString(env, "UI_PRIMARY_COLOR")) != null ? _B : "#10b981",
1339
+ accentColor: (_D = (_C = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _C : readString(env, "UI_ACCENT_COLOR")) != null ? _D : "#3b82f6",
1340
+ logoUrl: (_E = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _E : readString(env, "UI_LOGO_URL"),
1341
+ placeholder: (_G = (_F = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _F : readString(env, "UI_PLACEHOLDER")) != null ? _G : "Ask me anything\u2026",
1342
+ showSources: ((_I = (_H = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _H : readString(env, "UI_SHOW_SOURCES")) != null ? _I : "true") !== "false",
1343
+ 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.",
1344
+ visualStyle: (_M = (_L = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _L : readString(env, "UI_VISUAL_STYLE")) != null ? _M : "glass",
1345
+ borderRadius: (_O = (_N = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _N : readString(env, "UI_BORDER_RADIUS")) != null ? _O : "xl"
1532
1346
  },
1533
1347
  rag: {
1534
1348
  topK: readNumber(env, "RAG_TOP_K", 5),
@@ -1604,7 +1418,7 @@ var ConfigValidator = class {
1604
1418
  errors.push({
1605
1419
  field: "embedding",
1606
1420
  message: "Embedding config is required when using Anthropic LLM",
1607
- suggestion: 'Provide embedding config with provider (e.g., "openai")',
1421
+ suggestion: 'Provide embedding config with provider (e.g., "openai" or "ollama")',
1608
1422
  severity: "error"
1609
1423
  });
1610
1424
  }
@@ -1666,6 +1480,10 @@ var ConfigValidator = class {
1666
1480
  }
1667
1481
  return errors;
1668
1482
  }
1483
+ /**
1484
+ * Pinecone — only needs apiKey (environment was removed in SDK v7+).
1485
+ * Options key: { apiKey: string }
1486
+ */
1669
1487
  static validatePineconeConfig(config) {
1670
1488
  const errors = [];
1671
1489
  const opts = config.options;
@@ -1677,16 +1495,12 @@ var ConfigValidator = class {
1677
1495
  severity: "error"
1678
1496
  });
1679
1497
  }
1680
- if (!opts.environment) {
1681
- errors.push({
1682
- field: "vectorDb.options.environment",
1683
- message: "Pinecone environment is required",
1684
- suggestion: 'Set PINECONE_ENVIRONMENT environment variable (e.g., "gcp-starter")',
1685
- severity: "error"
1686
- });
1687
- }
1688
1498
  return errors;
1689
1499
  }
1500
+ /**
1501
+ * PostgreSQL / pgvector — needs a connection string.
1502
+ * Options key: { connectionString: string }
1503
+ */
1690
1504
  static validatePostgresConfig(config) {
1691
1505
  const errors = [];
1692
1506
  const opts = config.options;
@@ -1700,6 +1514,10 @@ var ConfigValidator = class {
1700
1514
  }
1701
1515
  return errors;
1702
1516
  }
1517
+ /**
1518
+ * MongoDB — needs uri, database, and collection.
1519
+ * Options keys: { uri: string, database: string, collection: string }
1520
+ */
1703
1521
  static validateMongoDBConfig(config) {
1704
1522
  const errors = [];
1705
1523
  const opts = config.options;
@@ -1729,27 +1547,30 @@ var ConfigValidator = class {
1729
1547
  }
1730
1548
  return errors;
1731
1549
  }
1550
+ /**
1551
+ * Milvus — accepts baseUrl OR uri (preferred) OR host+port.
1552
+ * MilvusProvider reads opts.baseUrl ?? opts.uri.
1553
+ * Options keys: { baseUrl?: string, uri?: string, host?: string, port?: number }
1554
+ */
1732
1555
  static validateMilvusConfig(config) {
1733
1556
  const errors = [];
1734
1557
  const opts = config.options;
1735
- if (!opts.host) {
1558
+ const hasBaseUrl = Boolean(opts.baseUrl || opts.uri);
1559
+ const hasHostPort = Boolean(opts.host && opts.port);
1560
+ if (!hasBaseUrl && !hasHostPort) {
1736
1561
  errors.push({
1737
- field: "vectorDb.options.host",
1738
- message: "Milvus host is required",
1739
- suggestion: "Set MILVUS_HOST environment variable",
1740
- severity: "error"
1741
- });
1742
- }
1743
- if (!opts.port) {
1744
- errors.push({
1745
- field: "vectorDb.options.port",
1746
- message: "Milvus port is required",
1747
- suggestion: "Set MILVUS_PORT environment variable (default: 19530)",
1562
+ field: "vectorDb.options.baseUrl",
1563
+ message: 'Milvus connection is required: provide baseUrl (e.g., "http://localhost:19530") or host + port',
1564
+ suggestion: "Set MILVUS_URL environment variable",
1748
1565
  severity: "error"
1749
1566
  });
1750
1567
  }
1751
1568
  return errors;
1752
1569
  }
1570
+ /**
1571
+ * Qdrant — needs baseUrl (or url alias).
1572
+ * Options keys: { baseUrl: string, apiKey?: string }
1573
+ */
1753
1574
  static validateQdrantConfig(config) {
1754
1575
  const errors = [];
1755
1576
  const opts = config.options;
@@ -1763,38 +1584,55 @@ var ConfigValidator = class {
1763
1584
  }
1764
1585
  return errors;
1765
1586
  }
1587
+ /**
1588
+ * ChromaDB — accepts baseUrl OR host.
1589
+ * ChromaDBProvider reads opts.baseUrl.
1590
+ * Options keys: { baseUrl?: string, host?: string, port?: number }
1591
+ */
1766
1592
  static validateChromaDBConfig(config) {
1767
1593
  const errors = [];
1768
1594
  const opts = config.options;
1769
- if (!opts.host && !opts.path) {
1595
+ if (!opts.baseUrl && !opts.host) {
1770
1596
  errors.push({
1771
- field: "vectorDb.options.host",
1772
- message: "ChromaDB host or path is required",
1773
- suggestion: "Set CHROMADB_HOST or CHROMADB_PATH environment variable",
1597
+ field: "vectorDb.options.baseUrl",
1598
+ message: 'ChromaDB connection is required: provide baseUrl (e.g., "http://localhost:8000") or host',
1599
+ suggestion: "Set CHROMADB_URL environment variable",
1774
1600
  severity: "error"
1775
1601
  });
1776
1602
  }
1777
1603
  return errors;
1778
1604
  }
1605
+ /**
1606
+ * Redis — accepts baseUrl OR url OR host+port.
1607
+ * RedisProvider reads opts.baseUrl.
1608
+ * Options keys: { baseUrl?: string, url?: string, host?: string, port?: number, apiKey?: string }
1609
+ */
1779
1610
  static validateRedisConfig(config) {
1780
1611
  const errors = [];
1781
1612
  const opts = config.options;
1782
- if (!opts.url && (!opts.host || !opts.port)) {
1613
+ const hasUrl = Boolean(opts.baseUrl || opts.url);
1614
+ const hasHostPort = Boolean(opts.host && opts.port);
1615
+ if (!hasUrl && !hasHostPort) {
1783
1616
  errors.push({
1784
- field: "vectorDb.options.url",
1785
- message: "Redis connection URL or host:port is required",
1786
- suggestion: "Set REDIS_URL or REDIS_HOST/REDIS_PORT environment variables",
1617
+ field: "vectorDb.options.baseUrl",
1618
+ message: "Redis connection is required: provide baseUrl/url or host + port",
1619
+ suggestion: "Set REDIS_URL environment variable",
1787
1620
  severity: "error"
1788
1621
  });
1789
1622
  }
1790
1623
  return errors;
1791
1624
  }
1625
+ /**
1626
+ * Weaviate — accepts baseUrl OR url.
1627
+ * WeaviateProvider reads opts.baseUrl.
1628
+ * Options keys: { baseUrl?: string, url?: string, apiKey?: string }
1629
+ */
1792
1630
  static validateWeaviateConfig(config) {
1793
1631
  const errors = [];
1794
1632
  const opts = config.options;
1795
- if (!opts.url) {
1633
+ if (!opts.baseUrl && !opts.url) {
1796
1634
  errors.push({
1797
- field: "vectorDb.options.url",
1635
+ field: "vectorDb.options.baseUrl",
1798
1636
  message: "Weaviate instance URL is required",
1799
1637
  suggestion: "Set WEAVIATE_URL environment variable",
1800
1638
  severity: "error"
@@ -1802,6 +1640,10 @@ var ConfigValidator = class {
1802
1640
  }
1803
1641
  return errors;
1804
1642
  }
1643
+ /**
1644
+ * Universal REST / custom REST adapter.
1645
+ * Options key: { baseUrl: string }
1646
+ */
1805
1647
  static validateRestConfig(config) {
1806
1648
  const errors = [];
1807
1649
  const opts = config.options;
@@ -1909,7 +1751,7 @@ var ConfigValidator = class {
1909
1751
  errors.push({
1910
1752
  field: "embedding.model",
1911
1753
  message: "Embedding model name is required",
1912
- suggestion: 'e.g., "text-embedding-3-small" for OpenAI',
1754
+ suggestion: 'e.g., "text-embedding-3-small" for OpenAI, "nomic-embed-text" for Ollama',
1913
1755
  severity: "error"
1914
1756
  });
1915
1757
  }
@@ -1924,7 +1766,7 @@ var ConfigValidator = class {
1924
1766
  if (config.provider === "ollama" && !config.baseUrl) {
1925
1767
  errors.push({
1926
1768
  field: "embedding.baseUrl",
1927
- message: "Ollama base URL is required",
1769
+ message: "Ollama base URL is required for embedding",
1928
1770
  suggestion: "Set EMBEDDING_BASE_URL environment variable",
1929
1771
  severity: "error"
1930
1772
  });
@@ -2101,17 +1943,433 @@ var DocumentChunker = class {
2101
1943
  }
2102
1944
  };
2103
1945
 
1946
+ // src/llm/providers/OpenAIProvider.ts
1947
+ var import_openai = __toESM(require("openai"));
1948
+ var OpenAIProvider = class {
1949
+ constructor(llmConfig, embeddingConfig) {
1950
+ if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
1951
+ this.client = new import_openai.default({ apiKey: llmConfig.apiKey });
1952
+ this.llmConfig = llmConfig;
1953
+ this.embeddingConfig = embeddingConfig;
1954
+ }
1955
+ async chat(messages, context, options) {
1956
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1957
+ const systemContent = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
1958
+
1959
+ Context:
1960
+ ${context}`;
1961
+ const systemMessage = {
1962
+ role: "system",
1963
+ content: systemContent.includes("{{context}}") ? systemContent.replace("{{context}}", context) : `${systemContent}
1964
+
1965
+ Context:
1966
+ ${context}`
1967
+ };
1968
+ const formattedMessages = [
1969
+ systemMessage,
1970
+ ...messages.map((m) => ({
1971
+ role: m.role,
1972
+ content: m.content
1973
+ }))
1974
+ ];
1975
+ const completion = await this.client.chat.completions.create({
1976
+ model: this.llmConfig.model,
1977
+ messages: formattedMessages,
1978
+ max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
1979
+ temperature: (_e = (_d = options == null ? void 0 : options.temperature) != null ? _d : this.llmConfig.temperature) != null ? _e : 0.7,
1980
+ stop: options == null ? void 0 : options.stop
1981
+ });
1982
+ return (_h = (_g = (_f = completion.choices[0]) == null ? void 0 : _f.message) == null ? void 0 : _g.content) != null ? _h : "";
1983
+ }
1984
+ async embed(text, options) {
1985
+ const results = await this.batchEmbed([text], options);
1986
+ return results[0];
1987
+ }
1988
+ async batchEmbed(texts, options) {
1989
+ var _a, _b, _c, _d, _e;
1990
+ 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";
1991
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
1992
+ const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
1993
+ const response = await client.embeddings.create({ model, input: texts });
1994
+ return response.data.map((d) => d.embedding);
1995
+ }
1996
+ async ping() {
1997
+ try {
1998
+ await this.client.models.list();
1999
+ return true;
2000
+ } catch (err) {
2001
+ console.error("[OpenAIProvider] Ping failed:", err);
2002
+ return false;
2003
+ }
2004
+ }
2005
+ };
2006
+
2007
+ // src/llm/providers/AnthropicProvider.ts
2008
+ var import_sdk = __toESM(require("@anthropic-ai/sdk"));
2009
+ var AnthropicProvider = class {
2010
+ constructor(llmConfig, embeddingConfig) {
2011
+ if (!llmConfig.apiKey) throw new Error("[AnthropicProvider] llmConfig.apiKey is required");
2012
+ this.client = new import_sdk.default({ apiKey: llmConfig.apiKey });
2013
+ this.llmConfig = llmConfig;
2014
+ this.embeddingConfig = embeddingConfig;
2015
+ }
2016
+ async chat(messages, context, options) {
2017
+ var _a, _b, _c;
2018
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the context below to answer the user's question accurately.
2019
+
2020
+ Context:
2021
+ ${context}`;
2022
+ const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
2023
+
2024
+ Context:
2025
+ ${context}`;
2026
+ const anthropicMessages = messages.map((m) => ({
2027
+ role: m.role === "assistant" ? "assistant" : "user",
2028
+ content: m.content
2029
+ }));
2030
+ const response = await this.client.messages.create({
2031
+ model: this.llmConfig.model,
2032
+ max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
2033
+ system,
2034
+ messages: anthropicMessages
2035
+ });
2036
+ const block = response.content[0];
2037
+ return block.type === "text" ? block.text : "";
2038
+ }
2039
+ /**
2040
+ * Anthropic does not offer an embedding API.
2041
+ * This method throws with a clear error so developers know to configure
2042
+ * a separate embedding provider (OpenAI or Ollama).
2043
+ */
2044
+ async embed(text, options) {
2045
+ void text;
2046
+ void options;
2047
+ throw new Error(
2048
+ '[AnthropicProvider] Anthropic does not provide an embedding API. Set embedding.provider to "openai" or "ollama" in your RagConfig.'
2049
+ );
2050
+ }
2051
+ async batchEmbed(texts, options) {
2052
+ void texts;
2053
+ void options;
2054
+ throw new Error(
2055
+ "[AnthropicProvider] Anthropic does not provide an embedding API."
2056
+ );
2057
+ }
2058
+ async ping() {
2059
+ try {
2060
+ await this.client.models.list();
2061
+ return true;
2062
+ } catch (err) {
2063
+ console.error("[AnthropicProvider] Ping failed:", err);
2064
+ return false;
2065
+ }
2066
+ }
2067
+ };
2068
+
2069
+ // src/llm/providers/OllamaProvider.ts
2070
+ var import_axios = __toESM(require("axios"));
2071
+ var OllamaProvider = class {
2072
+ constructor(llmConfig, embeddingConfig) {
2073
+ var _a;
2074
+ const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
2075
+ this.http = import_axios.default.create({ baseURL, timeout: 12e4 });
2076
+ this.llmConfig = llmConfig;
2077
+ this.embeddingConfig = embeddingConfig;
2078
+ }
2079
+ async chat(messages, context, options) {
2080
+ var _a, _b, _c, _d, _e;
2081
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
2082
+
2083
+ Context:
2084
+ ${context}`;
2085
+ const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
2086
+
2087
+ Context:
2088
+ ${context}`;
2089
+ const { data } = await this.http.post("/api/chat", {
2090
+ model: this.llmConfig.model,
2091
+ stream: false,
2092
+ options: {
2093
+ temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
2094
+ num_predict: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024
2095
+ },
2096
+ messages: [
2097
+ { role: "system", content: system },
2098
+ ...messages.map((m) => ({ role: m.role, content: m.content }))
2099
+ ]
2100
+ });
2101
+ return data.message.content;
2102
+ }
2103
+ async embed(text, options) {
2104
+ var _a, _b, _c, _d, _e, _f, _g;
2105
+ 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";
2106
+ const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
2107
+ const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
2108
+ const { data } = await client.post("/api/embeddings", {
2109
+ model,
2110
+ prompt: text
2111
+ });
2112
+ return data.embedding;
2113
+ }
2114
+ async batchEmbed(texts, options) {
2115
+ const vectors = [];
2116
+ for (const text of texts) {
2117
+ vectors.push(await this.embed(text, options));
2118
+ }
2119
+ return vectors;
2120
+ }
2121
+ async ping() {
2122
+ try {
2123
+ await this.http.get("/api/tags");
2124
+ return true;
2125
+ } catch (err) {
2126
+ console.error("[OllamaProvider] Ping failed:", err);
2127
+ return false;
2128
+ }
2129
+ }
2130
+ };
2131
+
2132
+ // src/llm/providers/UniversalLLMAdapter.ts
2133
+ var import_axios2 = __toESM(require("axios"));
2134
+ init_templateUtils();
2135
+
2136
+ // src/config/UniversalProfiles.ts
2137
+ var OPENAI_BASE = {
2138
+ chatPath: "/chat/completions",
2139
+ embedPath: "/embeddings",
2140
+ responseExtractPath: "choices[0].message.content",
2141
+ embedExtractPath: "data[0].embedding",
2142
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
2143
+ };
2144
+ var LLM_PROFILES = {
2145
+ "openai-compatible": OPENAI_BASE,
2146
+ "litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
2147
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
2148
+ }),
2149
+ "anthropic-claude": {
2150
+ chatPath: "/v1/messages",
2151
+ responseExtractPath: "content[0].text",
2152
+ headers: { "anthropic-version": "2023-06-01" },
2153
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
2154
+ },
2155
+ "google-gemini": {
2156
+ chatPath: "/v1beta/models/{{model}}:generateContent",
2157
+ responseExtractPath: "candidates[0].content.parts[0].text",
2158
+ chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
2159
+ },
2160
+ "github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
2161
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
2162
+ }),
2163
+ "ollama-standard": {
2164
+ chatPath: "/api/chat",
2165
+ embedPath: "/api/embeddings",
2166
+ responseExtractPath: "message.content",
2167
+ embedExtractPath: "embedding",
2168
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
2169
+ embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
2170
+ }
2171
+ };
2172
+ var VECTOR_PROFILES = {
2173
+ "pinecone-rest": {
2174
+ queryPath: "/query",
2175
+ upsertPath: "/vectors/upsert",
2176
+ responseExtractPath: "matches",
2177
+ idPath: "id",
2178
+ scorePath: "score",
2179
+ contentPath: "metadata.content",
2180
+ metadataPath: "metadata",
2181
+ queryPayloadTemplate: '{"vector":{{vector}},"topK":{{topK}},"includeMetadata":true,"namespace":"{{namespace}}"}'
2182
+ },
2183
+ "mongodb-atlas": {
2184
+ queryPath: "/action/aggregate",
2185
+ responseExtractPath: "documents",
2186
+ idPath: "_id",
2187
+ scorePath: "score",
2188
+ contentPath: "content",
2189
+ metadataPath: "metadata",
2190
+ 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"}}}]}'
2191
+ },
2192
+ "chromadb": {
2193
+ queryPath: "/api/v1/collections/{{index}}/query",
2194
+ upsertPath: "/api/v1/collections/{{index}}/add",
2195
+ responseExtractPath: "matches",
2196
+ idPath: "id",
2197
+ scorePath: "distance",
2198
+ contentPath: "document",
2199
+ metadataPath: "metadata"
2200
+ },
2201
+ "qdrant": {
2202
+ queryPath: "/collections/{{index}}/points/search",
2203
+ upsertPath: "/collections/{{index}}/points",
2204
+ responseExtractPath: "result",
2205
+ idPath: "id",
2206
+ scorePath: "score",
2207
+ contentPath: "payload.content",
2208
+ metadataPath: "payload"
2209
+ }
2210
+ };
2211
+
2212
+ // src/llm/providers/UniversalLLMAdapter.ts
2213
+ var UniversalLLMAdapter = class {
2214
+ constructor(config) {
2215
+ var _a, _b, _c, _d, _e, _f, _g;
2216
+ this.model = config.model;
2217
+ const llmConfig = config;
2218
+ const options = (_a = llmConfig.options) != null ? _a : {};
2219
+ let profile = {};
2220
+ if (typeof options.profile === "string") {
2221
+ profile = LLM_PROFILES[options.profile] || {};
2222
+ } else if (typeof options.profile === "object" && options.profile !== null) {
2223
+ profile = options.profile;
2224
+ }
2225
+ this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
2226
+ this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
2227
+ this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
2228
+ this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
2229
+ const baseUrl = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl;
2230
+ if (!baseUrl) {
2231
+ throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
2232
+ }
2233
+ this.http = import_axios2.default.create({
2234
+ baseURL: baseUrl,
2235
+ headers: __spreadValues(__spreadValues({
2236
+ "Content-Type": "application/json"
2237
+ }, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {}),
2238
+ timeout: (_g = this.opts.timeout) != null ? _g : 6e4
2239
+ });
2240
+ }
2241
+ async chat(messages, context) {
2242
+ var _a, _b;
2243
+ const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
2244
+ const formattedMessages = [
2245
+ { role: "system", content: `${this.systemPrompt}
2246
+
2247
+ Context:
2248
+ ${context != null ? context : "None"}` },
2249
+ ...messages
2250
+ ];
2251
+ let payload;
2252
+ if (this.opts.chatPayloadTemplate) {
2253
+ payload = buildPayload(this.opts.chatPayloadTemplate, {
2254
+ model: this.model,
2255
+ messages: formattedMessages,
2256
+ maxTokens: this.maxTokens,
2257
+ temperature: this.temperature
2258
+ });
2259
+ } else {
2260
+ payload = {
2261
+ model: this.model,
2262
+ messages: formattedMessages,
2263
+ max_tokens: this.maxTokens,
2264
+ temperature: this.temperature
2265
+ };
2266
+ }
2267
+ const { data } = await this.http.post(path, payload);
2268
+ const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
2269
+ const result = resolvePath(data, extractPath);
2270
+ if (result === void 0) {
2271
+ throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
2272
+ }
2273
+ return String(result);
2274
+ }
2275
+ async embed(text) {
2276
+ var _a, _b;
2277
+ const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
2278
+ let payload;
2279
+ if (this.opts.embedPayloadTemplate) {
2280
+ payload = buildPayload(this.opts.embedPayloadTemplate, {
2281
+ model: this.model,
2282
+ input: text
2283
+ });
2284
+ } else {
2285
+ payload = {
2286
+ model: this.model,
2287
+ input: text
2288
+ };
2289
+ }
2290
+ const { data } = await this.http.post(path, payload);
2291
+ const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
2292
+ const vector = resolvePath(data, extractPath);
2293
+ if (!Array.isArray(vector)) {
2294
+ throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
2295
+ }
2296
+ return vector;
2297
+ }
2298
+ async batchEmbed(texts) {
2299
+ const vectors = [];
2300
+ for (const text of texts) {
2301
+ vectors.push(await this.embed(text));
2302
+ }
2303
+ return vectors;
2304
+ }
2305
+ async ping() {
2306
+ try {
2307
+ if (this.opts.pingPath) {
2308
+ await this.http.get(this.opts.pingPath);
2309
+ }
2310
+ return true;
2311
+ } catch (err) {
2312
+ console.error("[UniversalLLMAdapter] Ping failed:", err);
2313
+ return false;
2314
+ }
2315
+ }
2316
+ };
2317
+
2318
+ // src/llm/LLMFactory.ts
2319
+ var LLMFactory = class _LLMFactory {
2320
+ static create(llmConfig, embeddingConfig) {
2321
+ var _a;
2322
+ switch (llmConfig.provider) {
2323
+ case "openai":
2324
+ return new OpenAIProvider(llmConfig, embeddingConfig);
2325
+ case "anthropic":
2326
+ return new AnthropicProvider(llmConfig, embeddingConfig);
2327
+ case "ollama":
2328
+ return new OllamaProvider(llmConfig, embeddingConfig);
2329
+ case "rest":
2330
+ case "universal_rest":
2331
+ case "custom":
2332
+ return new UniversalLLMAdapter(llmConfig);
2333
+ default:
2334
+ if (llmConfig.baseUrl || ((_a = llmConfig.options) == null ? void 0 : _a.baseUrl)) {
2335
+ return new UniversalLLMAdapter(llmConfig);
2336
+ }
2337
+ throw new Error(
2338
+ `[LLMFactory] Unknown provider "${llmConfig.provider}". Supported: openai | anthropic | ollama | rest | custom`
2339
+ );
2340
+ }
2341
+ }
2342
+ /**
2343
+ * Creates a dedicated embedding-only provider.
2344
+ * Useful when the LLM provider (e.g. Anthropic) doesn't support embeddings.
2345
+ */
2346
+ static createEmbeddingProvider(embeddingConfig) {
2347
+ const fakeLLMConfig = {
2348
+ provider: embeddingConfig.provider,
2349
+ model: embeddingConfig.model,
2350
+ apiKey: embeddingConfig.apiKey,
2351
+ baseUrl: embeddingConfig.baseUrl,
2352
+ options: embeddingConfig.options
2353
+ };
2354
+ return _LLMFactory.create(fakeLLMConfig, embeddingConfig);
2355
+ }
2356
+ };
2357
+
2104
2358
  // src/core/ProviderRegistry.ts
2105
- init_LLMFactory();
2106
2359
  var ProviderRegistry = class {
2107
2360
  /**
2108
- * Register a custom vector provider.
2361
+ * Register a custom vector provider class by name.
2362
+ * The name must match the provider value used in VectorDBConfig.provider.
2363
+ *
2364
+ * @example
2365
+ * ProviderRegistry.registerVectorProvider('my-db', MyCustomProvider);
2109
2366
  */
2110
2367
  static registerVectorProvider(name, providerClass) {
2111
2368
  this.vectorProviders[name] = providerClass;
2112
2369
  }
2113
2370
  /**
2114
2371
  * Creates a vector database provider based on the configuration.
2372
+ * Built-in providers are dynamically imported to avoid bundling all SDKs.
2115
2373
  */
2116
2374
  static async createVectorProvider(config) {
2117
2375
  const { provider } = config;
@@ -2119,33 +2377,48 @@ var ProviderRegistry = class {
2119
2377
  return new this.vectorProviders[provider](config);
2120
2378
  }
2121
2379
  switch (provider) {
2122
- case "pinecone":
2380
+ case "pinecone": {
2123
2381
  const { PineconeProvider: PineconeProvider2 } = await Promise.resolve().then(() => (init_PineconeProvider(), PineconeProvider_exports));
2124
2382
  return new PineconeProvider2(config);
2383
+ }
2125
2384
  case "pgvector":
2126
- case "postgresql":
2385
+ case "postgresql": {
2127
2386
  const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
2128
2387
  return new PostgreSQLProvider2(config);
2129
- case "mongodb":
2388
+ }
2389
+ case "mongodb": {
2130
2390
  const { MongoDBProvider: MongoDBProvider2 } = await Promise.resolve().then(() => (init_MongoDBProvider(), MongoDBProvider_exports));
2131
2391
  return new MongoDBProvider2(config);
2132
- case "milvus":
2392
+ }
2393
+ case "milvus": {
2133
2394
  const { MilvusProvider: MilvusProvider2 } = await Promise.resolve().then(() => (init_MilvusProvider(), MilvusProvider_exports));
2134
2395
  return new MilvusProvider2(config);
2135
- case "qdrant":
2396
+ }
2397
+ case "qdrant": {
2136
2398
  const { QdrantProvider: QdrantProvider2 } = await Promise.resolve().then(() => (init_QdrantProvider(), QdrantProvider_exports));
2137
2399
  return new QdrantProvider2(config);
2138
- case "chromadb":
2400
+ }
2401
+ case "chromadb": {
2139
2402
  const { ChromaDBProvider: ChromaDBProvider2 } = await Promise.resolve().then(() => (init_ChromaDBProvider(), ChromaDBProvider_exports));
2140
2403
  return new ChromaDBProvider2(config);
2141
- case "redis":
2404
+ }
2405
+ case "redis": {
2142
2406
  const { RedisProvider: RedisProvider2 } = await Promise.resolve().then(() => (init_RedisProvider(), RedisProvider_exports));
2143
2407
  return new RedisProvider2(config);
2144
- case "weaviate":
2408
+ }
2409
+ case "weaviate": {
2145
2410
  const { WeaviateProvider: WeaviateProvider2 } = await Promise.resolve().then(() => (init_WeaviateProvider(), WeaviateProvider_exports));
2146
2411
  return new WeaviateProvider2(config);
2412
+ }
2413
+ case "universal_rest":
2414
+ case "rest": {
2415
+ const { UniversalVectorProvider: UniversalVectorProvider2 } = await Promise.resolve().then(() => (init_UniversalVectorProvider(), UniversalVectorProvider_exports));
2416
+ return new UniversalVectorProvider2(config);
2417
+ }
2147
2418
  default:
2148
- throw new Error(`[ProviderRegistry] Unsupported vector provider: ${provider}`);
2419
+ throw new Error(
2420
+ `[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).`
2421
+ );
2149
2422
  }
2150
2423
  }
2151
2424
  /**
@@ -2377,7 +2650,90 @@ ${errorMessages}`
2377
2650
  ${errorMessages}`
2378
2651
  );
2379
2652
  }
2380
- return { results, errors, totalProcessed, totalFailed };
2653
+ return { results, errors, totalProcessed, totalFailed };
2654
+ }
2655
+ };
2656
+
2657
+ // src/config/EmbeddingStrategy.ts
2658
+ var EmbeddingStrategy = /* @__PURE__ */ ((EmbeddingStrategy2) => {
2659
+ EmbeddingStrategy2["INTEGRATED"] = "integrated";
2660
+ EmbeddingStrategy2["SEPARATE"] = "separate";
2661
+ EmbeddingStrategy2["EXTERNAL"] = "external";
2662
+ return EmbeddingStrategy2;
2663
+ })(EmbeddingStrategy || {});
2664
+ var EmbeddingStrategyResolver = class {
2665
+ /**
2666
+ * Determine strategy based on LLM and embedding configs
2667
+ */
2668
+ static determineStrategy(llmConfig, embeddingConfig) {
2669
+ if (!embeddingConfig) {
2670
+ return this.supportsEmbedding(llmConfig.provider) ? "integrated" /* INTEGRATED */ : "separate" /* SEPARATE */;
2671
+ }
2672
+ if (embeddingConfig.provider !== llmConfig.provider) {
2673
+ return "separate" /* SEPARATE */;
2674
+ }
2675
+ if (embeddingConfig.model !== llmConfig.model) {
2676
+ return "external" /* EXTERNAL */;
2677
+ }
2678
+ return "integrated" /* INTEGRATED */;
2679
+ }
2680
+ /**
2681
+ * Resolve and initialize providers according to the strategy
2682
+ */
2683
+ static async resolve(llmConfig, embeddingConfig) {
2684
+ const strategy = this.determineStrategy(llmConfig, embeddingConfig);
2685
+ const llmProvider = LLMFactory.create(llmConfig, embeddingConfig);
2686
+ let embeddingProvider;
2687
+ switch (strategy) {
2688
+ case "integrated" /* INTEGRATED */:
2689
+ embeddingProvider = llmProvider;
2690
+ break;
2691
+ case "separate" /* SEPARATE */:
2692
+ if (!embeddingConfig) {
2693
+ throw new Error(
2694
+ "[EmbeddingStrategyResolver] SEPARATE strategy requires embeddingConfig"
2695
+ );
2696
+ }
2697
+ embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
2698
+ break;
2699
+ case "external" /* EXTERNAL */:
2700
+ if (!embeddingConfig) {
2701
+ throw new Error(
2702
+ "[EmbeddingStrategyResolver] EXTERNAL strategy requires embeddingConfig"
2703
+ );
2704
+ }
2705
+ embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
2706
+ break;
2707
+ default:
2708
+ throw new Error(`[EmbeddingStrategyResolver] Unknown strategy: ${strategy}`);
2709
+ }
2710
+ return {
2711
+ strategy,
2712
+ embeddingProvider,
2713
+ llmProvider
2714
+ };
2715
+ }
2716
+ /**
2717
+ * Check if an LLM provider natively supports embeddings
2718
+ */
2719
+ static supportsEmbedding(provider) {
2720
+ const providersWithEmbedding = ["openai", "ollama", "rest", "universal_rest"];
2721
+ return providersWithEmbedding.includes(provider);
2722
+ }
2723
+ /**
2724
+ * Get a human-readable description of the strategy
2725
+ */
2726
+ static getDescription(strategy) {
2727
+ switch (strategy) {
2728
+ case "integrated" /* INTEGRATED */:
2729
+ return "Using LLM provider for both chat and embeddings";
2730
+ case "separate" /* SEPARATE */:
2731
+ return "Using separate embedding provider";
2732
+ case "external" /* EXTERNAL */:
2733
+ return "Using external embedding service";
2734
+ default:
2735
+ return "Unknown strategy";
2736
+ }
2381
2737
  }
2382
2738
  };
2383
2739
 
@@ -2395,18 +2751,17 @@ var Pipeline = class {
2395
2751
  async initialize() {
2396
2752
  if (this.initialised) return;
2397
2753
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
2398
- this.llmProvider = ProviderRegistry.createLLMProvider(this.config.llm, this.config.embedding);
2399
- if (this.config.llm.provider === "anthropic") {
2400
- const { LLMFactory: LLMFactory2 } = await Promise.resolve().then(() => (init_LLMFactory(), LLMFactory_exports));
2401
- this.embeddingProvider = LLMFactory2.createEmbeddingProvider(this.config.embedding);
2402
- } else {
2403
- this.embeddingProvider = this.llmProvider;
2404
- }
2754
+ const { llmProvider, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
2755
+ this.config.llm,
2756
+ this.config.embedding
2757
+ );
2758
+ this.llmProvider = llmProvider;
2759
+ this.embeddingProvider = embeddingProvider;
2405
2760
  await this.vectorDB.initialize();
2406
2761
  this.initialised = true;
2407
2762
  }
2408
2763
  /**
2409
- * Ingest documents with automatic chunking, embedding, and batch processing.
2764
+ * Ingest documents with automatic chunking, embedding, and batch upsert.
2410
2765
  * Handles retries for transient failures.
2411
2766
  */
2412
2767
  async ingest(documents, namespace) {
@@ -2419,19 +2774,18 @@ var Pipeline = class {
2419
2774
  docId: doc.docId,
2420
2775
  metadata: doc.metadata
2421
2776
  });
2422
- const batchOptions = {
2777
+ const embedBatchOptions = {
2423
2778
  batchSize: 50,
2424
- // Embedding batch size
2425
2779
  maxRetries: 3,
2426
2780
  initialDelayMs: 100
2427
2781
  };
2428
2782
  const vectors = await BatchProcessor.mapWithRetry(
2429
2783
  chunks.map((c) => c.content),
2430
2784
  (text) => this.embeddingProvider.embed(text),
2431
- batchOptions
2785
+ embedBatchOptions
2432
2786
  );
2433
2787
  if (vectors.length !== chunks.length) {
2434
- throw new Error(`Embedding failed: got ${vectors.length} vectors for ${chunks.length} chunks`);
2788
+ throw new Error(`Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks`);
2435
2789
  }
2436
2790
  const upsertDocs = chunks.map((chunk, i) => ({
2437
2791
  id: chunk.id,
@@ -2458,10 +2812,7 @@ var Pipeline = class {
2458
2812
  });
2459
2813
  } catch (error) {
2460
2814
  console.error(`[Pipeline] Failed to ingest document ${doc.docId}:`, error);
2461
- results.push({
2462
- docId: doc.docId,
2463
- chunksIngested: 0
2464
- });
2815
+ results.push({ docId: doc.docId, chunksIngested: 0 });
2465
2816
  }
2466
2817
  }
2467
2818
  return results;
@@ -2491,7 +2842,6 @@ ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
2491
2842
  var ProviderHealthCheck = class {
2492
2843
  /**
2493
2844
  * Validates vector database configuration before initialization.
2494
- * Performs connectivity checks and verifies required resources exist.
2495
2845
  */
2496
2846
  static async checkVectorProvider(config) {
2497
2847
  const timestamp = Date.now();
@@ -2499,7 +2849,6 @@ var ProviderHealthCheck = class {
2499
2849
  projectId: "health-check",
2500
2850
  vectorDb: config,
2501
2851
  llm: { provider: "openai", model: "gpt-4o" },
2502
- // dummy
2503
2852
  embedding: { provider: "openai", model: "text-embedding-3-small" }
2504
2853
  });
2505
2854
  const vectorDbErrors = configErrors.filter((e) => e.field.startsWith("vectorDb"));
@@ -2569,10 +2918,7 @@ var ProviderHealthCheck = class {
2569
2918
  return {
2570
2919
  healthy: true,
2571
2920
  provider: "pinecone",
2572
- capabilities: {
2573
- indexes: indexNames.length,
2574
- targetIndex: config.indexName
2575
- },
2921
+ capabilities: { indexes: indexNames.length, targetIndex: config.indexName },
2576
2922
  timestamp
2577
2923
  };
2578
2924
  } catch (error) {
@@ -2591,9 +2937,7 @@ var ProviderHealthCheck = class {
2591
2937
  const client = new Client({ connectionString: opts.connectionString });
2592
2938
  await client.connect();
2593
2939
  const result = await client.query(`
2594
- SELECT EXISTS(
2595
- SELECT 1 FROM pg_extension WHERE extname = 'vector'
2596
- );
2940
+ SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');
2597
2941
  `);
2598
2942
  const hasVector = result.rows[0].exists;
2599
2943
  await client.end();
@@ -2628,7 +2972,7 @@ var ProviderHealthCheck = class {
2628
2972
  provider: "mongodb",
2629
2973
  capabilities: {
2630
2974
  collections: collectionNames.length,
2631
- targetCollection: hasCollection ? opts.collection : "NOT FOUND"
2975
+ targetCollection: hasCollection ? opts.collection : "NOT FOUND (will be created on first insert)"
2632
2976
  },
2633
2977
  timestamp
2634
2978
  };
@@ -2641,16 +2985,16 @@ var ProviderHealthCheck = class {
2641
2985
  };
2642
2986
  }
2643
2987
  }
2988
+ /**
2989
+ * Milvus health check — uses baseUrl/uri (matching MilvusProvider constructor).
2990
+ */
2644
2991
  static async checkMilvus(config, timestamp) {
2645
2992
  const opts = config.options;
2646
- const host = opts.host || "localhost";
2647
- const port = opts.port || 19530;
2993
+ const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : "http://localhost:19530");
2648
2994
  try {
2649
2995
  const controller = new AbortController();
2650
2996
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
2651
- const response = await fetch(`http://${host}:${port}/healthz`, {
2652
- signal: controller.signal
2653
- });
2997
+ const response = await fetch(`${baseUrl}/v1/health`, { signal: controller.signal });
2654
2998
  clearTimeout(timeoutId);
2655
2999
  if (!response.ok) {
2656
3000
  throw new Error(`Health check returned ${response.status}`);
@@ -2658,7 +3002,7 @@ var ProviderHealthCheck = class {
2658
3002
  return {
2659
3003
  healthy: true,
2660
3004
  provider: "milvus",
2661
- capabilities: { endpoint: `${host}:${port}` },
3005
+ capabilities: { endpoint: baseUrl },
2662
3006
  timestamp
2663
3007
  };
2664
3008
  } catch (error) {
@@ -2670,17 +3014,18 @@ var ProviderHealthCheck = class {
2670
3014
  };
2671
3015
  }
2672
3016
  }
3017
+ /**
3018
+ * Qdrant health check — uses baseUrl (matching QdrantProvider constructor).
3019
+ */
2673
3020
  static async checkQdrant(config, timestamp) {
2674
3021
  const opts = config.options;
2675
- const baseUrl = opts.baseUrl || opts.url || "http://localhost:6333";
3022
+ const baseUrl = (opts.baseUrl || opts.url || "http://localhost:6333").replace(/\/$/, "");
2676
3023
  try {
2677
3024
  const apiKey = opts.apiKey;
2678
3025
  const response = await fetch(`${baseUrl}/`, {
2679
3026
  headers: apiKey ? { "api-key": apiKey } : {}
2680
3027
  });
2681
- if (!response.ok) {
2682
- throw new Error(`Health check returned ${response.status}`);
2683
- }
3028
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2684
3029
  const health = await response.json();
2685
3030
  return {
2686
3031
  healthy: true,
@@ -2697,19 +3042,19 @@ var ProviderHealthCheck = class {
2697
3042
  };
2698
3043
  }
2699
3044
  }
3045
+ /**
3046
+ * ChromaDB health check — uses baseUrl/host (matching ChromaDBProvider constructor).
3047
+ */
2700
3048
  static async checkChromaDB(config, timestamp) {
2701
3049
  const opts = config.options;
2702
- const host = opts.host || "localhost";
2703
- const port = opts.port || 8e3;
3050
+ const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : "http://localhost:8000");
2704
3051
  try {
2705
- const response = await fetch(`http://${host}:${port}/api/v1/heartbeat`);
2706
- if (!response.ok) {
2707
- throw new Error(`Health check returned ${response.status}`);
2708
- }
3052
+ const response = await fetch(`${baseUrl}/api/v1/heartbeat`);
3053
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2709
3054
  return {
2710
3055
  healthy: true,
2711
3056
  provider: "chromadb",
2712
- capabilities: { endpoint: `${host}:${port}` },
3057
+ capabilities: { endpoint: baseUrl },
2713
3058
  timestamp
2714
3059
  };
2715
3060
  } catch (error) {
@@ -2721,38 +3066,43 @@ var ProviderHealthCheck = class {
2721
3066
  };
2722
3067
  }
2723
3068
  }
3069
+ /**
3070
+ * Redis health check — Redis is TCP-only (no HTTP endpoint).
3071
+ * We report healthy=true with a note; actual connectivity is validated at first operation.
3072
+ */
2724
3073
  static async checkRedis(config, timestamp) {
2725
3074
  const opts = config.options;
2726
- const url = opts.url || `redis://${opts.host}:${opts.port}`;
2727
- try {
2728
- await fetch(url);
2729
- return {
2730
- healthy: true,
2731
- provider: "redis",
2732
- capabilities: { endpoint: url },
2733
- timestamp
2734
- };
2735
- } catch (error) {
2736
- return {
2737
- healthy: false,
2738
- provider: "redis",
2739
- error: `Connection check failed: ${error instanceof Error ? error.message : String(error)}. Ensure Redis is running at ${url}`,
2740
- timestamp
2741
- };
3075
+ const url = opts.baseUrl || opts.url || (opts.host && opts.port ? `redis://${opts.host}:${opts.port}` : "redis://localhost:6379");
3076
+ if (url.startsWith("http")) {
3077
+ try {
3078
+ await fetch(url);
3079
+ return { healthy: true, provider: "redis", capabilities: { endpoint: url }, timestamp };
3080
+ } catch (e) {
3081
+ }
2742
3082
  }
3083
+ return {
3084
+ healthy: true,
3085
+ provider: "redis",
3086
+ capabilities: {
3087
+ endpoint: url,
3088
+ note: "Redis uses TCP; connectivity is validated on first operation."
3089
+ },
3090
+ timestamp
3091
+ };
2743
3092
  }
3093
+ /**
3094
+ * Weaviate health check — uses baseUrl/url (matching WeaviateProvider constructor).
3095
+ */
2744
3096
  static async checkWeaviate(config, timestamp) {
2745
3097
  const opts = config.options;
2746
- const url = (opts.url || "http://localhost:8080").replace(/\/$/, "");
3098
+ const baseUrl = (opts.baseUrl || opts.url || "http://localhost:8080").replace(/\/$/, "");
2747
3099
  try {
2748
- const response = await fetch(`${url}/.well-known/ready`);
2749
- if (!response.ok) {
2750
- throw new Error(`Health check returned ${response.status}`);
2751
- }
3100
+ const response = await fetch(`${baseUrl}/v1/.well-known/ready`);
3101
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2752
3102
  return {
2753
3103
  healthy: true,
2754
3104
  provider: "weaviate",
2755
- capabilities: { endpoint: url },
3105
+ capabilities: { endpoint: baseUrl },
2756
3106
  timestamp
2757
3107
  };
2758
3108
  } catch (error) {
@@ -2768,12 +3118,7 @@ var ProviderHealthCheck = class {
2768
3118
  const opts = config.options;
2769
3119
  const baseUrl = (opts.baseUrl || "").replace(/\/$/, "");
2770
3120
  if (!baseUrl) {
2771
- return {
2772
- healthy: false,
2773
- provider: "rest",
2774
- error: "baseUrl is required",
2775
- timestamp
2776
- };
3121
+ return { healthy: false, provider: "rest", error: "baseUrl is required", timestamp };
2777
3122
  }
2778
3123
  try {
2779
3124
  const response = await fetch(`${baseUrl}/health`, {
@@ -2836,11 +3181,7 @@ var ProviderHealthCheck = class {
2836
3181
  return {
2837
3182
  healthy: true,
2838
3183
  provider: "openai",
2839
- capabilities: {
2840
- model: config.model,
2841
- available: hasModel,
2842
- totalModels: models.data.length
2843
- },
3184
+ capabilities: { model: config.model, available: hasModel, totalModels: models.data.length },
2844
3185
  timestamp
2845
3186
  };
2846
3187
  } catch (error) {
@@ -2861,12 +3202,7 @@ var ProviderHealthCheck = class {
2861
3202
  max_tokens: 10,
2862
3203
  messages: [{ role: "user", content: "ping" }]
2863
3204
  });
2864
- return {
2865
- healthy: true,
2866
- provider: "anthropic",
2867
- capabilities: { model: config.model },
2868
- timestamp
2869
- };
3205
+ return { healthy: true, provider: "anthropic", capabilities: { model: config.model }, timestamp };
2870
3206
  } catch (error) {
2871
3207
  return {
2872
3208
  healthy: false,
@@ -2880,20 +3216,14 @@ var ProviderHealthCheck = class {
2880
3216
  const baseUrl = (config.baseUrl || "http://localhost:11434").replace(/\/$/, "");
2881
3217
  try {
2882
3218
  const response = await fetch(`${baseUrl}/api/tags`);
2883
- if (!response.ok) {
2884
- throw new Error(`Health check returned ${response.status}`);
2885
- }
3219
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
2886
3220
  const data = await response.json();
2887
3221
  const models = data.models || [];
2888
3222
  const hasModel = models.some((m) => m.name === config.model);
2889
3223
  return {
2890
3224
  healthy: true,
2891
3225
  provider: "ollama",
2892
- capabilities: {
2893
- model: config.model,
2894
- available: hasModel,
2895
- totalModels: models.length
2896
- },
3226
+ capabilities: { model: config.model, available: hasModel, totalModels: models.length },
2897
3227
  timestamp
2898
3228
  };
2899
3229
  } catch (error) {
@@ -2910,18 +3240,11 @@ var ProviderHealthCheck = class {
2910
3240
  const baseUrlRaw = config.baseUrl || ((_a = config.options) == null ? void 0 : _a.baseUrl);
2911
3241
  const baseUrl = (typeof baseUrlRaw === "string" ? baseUrlRaw : "").replace(/\/$/, "");
2912
3242
  if (!baseUrl) {
2913
- return {
2914
- healthy: false,
2915
- provider: config.provider,
2916
- error: "baseUrl is required",
2917
- timestamp
2918
- };
3243
+ return { healthy: false, provider: config.provider, error: "baseUrl is required", timestamp };
2919
3244
  }
2920
3245
  try {
2921
3246
  const headers = (_b = config.options) == null ? void 0 : _b.headers;
2922
- const response = await fetch(`${baseUrl}/health`, {
2923
- headers: headers || void 0
2924
- });
3247
+ const response = await fetch(`${baseUrl}/health`, { headers: headers || void 0 });
2925
3248
  return {
2926
3249
  healthy: response.ok,
2927
3250
  provider: config.provider,
@@ -2938,7 +3261,7 @@ var ProviderHealthCheck = class {
2938
3261
  }
2939
3262
  }
2940
3263
  /**
2941
- * Runs comprehensive health checks on all configured providers.
3264
+ * Runs comprehensive health checks on all configured providers in parallel.
2942
3265
  */
2943
3266
  static async checkAll(vectorDbConfig, llmConfig, embeddingConfig) {
2944
3267
  const [vectorDb, llm, embedding] = await Promise.all([
@@ -3015,23 +3338,278 @@ var VectorPlugin = class {
3015
3338
  }
3016
3339
  };
3017
3340
 
3018
- // src/server.ts
3019
- init_BaseVectorProvider();
3020
- init_PineconeProvider();
3021
- init_PostgreSQLProvider();
3022
- init_MongoDBProvider();
3023
- init_MilvusProvider();
3024
- init_QdrantProvider();
3025
- init_ChromaDBProvider();
3026
- init_RedisProvider();
3027
- init_WeaviateProvider();
3028
- init_LLMFactory();
3029
- init_OpenAIProvider();
3030
- init_AnthropicProvider();
3031
- init_OllamaProvider();
3032
-
3033
- // src/handlers/index.ts
3034
- var import_server = require("next/server");
3341
+ // src/config/ConfigBuilder.ts
3342
+ var ConfigBuilder = class {
3343
+ constructor() {
3344
+ this.config = {
3345
+ projectId: "default-project",
3346
+ rag: {
3347
+ chunkSize: 1e3,
3348
+ chunkOverlap: 200,
3349
+ topK: 5
3350
+ }
3351
+ };
3352
+ }
3353
+ /**
3354
+ * Set the project/application ID for namespacing
3355
+ */
3356
+ projectId(id) {
3357
+ this.config.projectId = id;
3358
+ return this;
3359
+ }
3360
+ /**
3361
+ * Configure the vector database provider
3362
+ */
3363
+ vectorDb(provider, options) {
3364
+ var _a;
3365
+ if (provider === "auto") {
3366
+ this.config.vectorDb = this.autoDetectVectorDb();
3367
+ } else {
3368
+ this.config.vectorDb = {
3369
+ provider,
3370
+ indexName: (_a = options == null ? void 0 : options.indexName) != null ? _a : "default",
3371
+ options: __spreadValues({}, options)
3372
+ };
3373
+ }
3374
+ return this;
3375
+ }
3376
+ /**
3377
+ * Configure the LLM provider for chat
3378
+ */
3379
+ llm(provider, model, apiKey, options) {
3380
+ var _a, _b;
3381
+ if (provider === "auto") {
3382
+ this.config.llm = this.autoDetectLLM();
3383
+ } else {
3384
+ this.config.llm = {
3385
+ provider,
3386
+ model: model != null ? model : "default-model",
3387
+ apiKey,
3388
+ systemPrompt: options == null ? void 0 : options.systemPrompt,
3389
+ maxTokens: (_a = options == null ? void 0 : options.maxTokens) != null ? _a : 1024,
3390
+ temperature: (_b = options == null ? void 0 : options.temperature) != null ? _b : 0.7,
3391
+ baseUrl: options == null ? void 0 : options.baseUrl,
3392
+ options
3393
+ };
3394
+ }
3395
+ return this;
3396
+ }
3397
+ /**
3398
+ * Configure the embedding provider
3399
+ */
3400
+ embedding(provider, model, apiKey, options) {
3401
+ if (provider === "auto") {
3402
+ this.config.embedding = this.autoDetectEmbedding();
3403
+ } else {
3404
+ this.config.embedding = {
3405
+ provider,
3406
+ model: model != null ? model : "default-embedding",
3407
+ apiKey,
3408
+ baseUrl: options == null ? void 0 : options.baseUrl,
3409
+ options
3410
+ };
3411
+ }
3412
+ return this;
3413
+ }
3414
+ /**
3415
+ * Set RAG-specific parameters
3416
+ */
3417
+ rag(options) {
3418
+ var _a;
3419
+ this.config.rag = __spreadValues(__spreadValues({}, (_a = this.config.rag) != null ? _a : {}), options);
3420
+ return this;
3421
+ }
3422
+ /**
3423
+ * Set UI/UX parameters
3424
+ */
3425
+ ui(options) {
3426
+ this.config.ui = options;
3427
+ return this;
3428
+ }
3429
+ /**
3430
+ * Build and return the configuration
3431
+ */
3432
+ build() {
3433
+ const finalConfig = this.config;
3434
+ return finalConfig;
3435
+ }
3436
+ /**
3437
+ * Build and return as JSON for serialization
3438
+ */
3439
+ toJSON() {
3440
+ return JSON.stringify(this.build());
3441
+ }
3442
+ // ============================================================================
3443
+ // Private helper methods for auto-detection
3444
+ // ============================================================================
3445
+ autoDetectVectorDb() {
3446
+ if (process.env.PINECONE_API_KEY && process.env.PINECONE_INDEX) {
3447
+ return {
3448
+ provider: "pinecone",
3449
+ indexName: process.env.PINECONE_INDEX,
3450
+ options: { apiKey: process.env.PINECONE_API_KEY }
3451
+ };
3452
+ }
3453
+ if (process.env.QDRANT_URL) {
3454
+ return {
3455
+ provider: "qdrant",
3456
+ indexName: process.env.QDRANT_COLLECTION || "documents",
3457
+ options: {
3458
+ url: process.env.QDRANT_URL,
3459
+ apiKey: process.env.QDRANT_API_KEY
3460
+ }
3461
+ };
3462
+ }
3463
+ if (process.env.DATABASE_URL) {
3464
+ return {
3465
+ provider: "postgresql",
3466
+ indexName: process.env.PG_TABLE || "documents",
3467
+ options: {
3468
+ connectionString: process.env.DATABASE_URL
3469
+ }
3470
+ };
3471
+ }
3472
+ if (process.env.MONGODB_URI) {
3473
+ return {
3474
+ provider: "mongodb",
3475
+ indexName: process.env.MONGODB_COLLECTION || "documents",
3476
+ options: {
3477
+ uri: process.env.MONGODB_URI,
3478
+ database: process.env.MONGODB_DB || "ai_db",
3479
+ collection: process.env.MONGODB_COLLECTION || "documents"
3480
+ }
3481
+ };
3482
+ }
3483
+ if (process.env.REDIS_URL) {
3484
+ return {
3485
+ provider: "redis",
3486
+ indexName: process.env.REDIS_INDEX || "documents",
3487
+ options: {
3488
+ url: process.env.REDIS_URL
3489
+ }
3490
+ };
3491
+ }
3492
+ return {
3493
+ provider: "qdrant",
3494
+ indexName: "documents",
3495
+ options: {
3496
+ url: process.env.QDRANT_URL || "http://localhost:6333"
3497
+ }
3498
+ };
3499
+ }
3500
+ autoDetectLLM() {
3501
+ if (process.env.OPENAI_API_KEY) {
3502
+ return {
3503
+ provider: "openai",
3504
+ model: process.env.OPENAI_MODEL || "gpt-4o-mini",
3505
+ apiKey: process.env.OPENAI_API_KEY,
3506
+ maxTokens: parseInt(process.env.OPENAI_MAX_TOKENS || "1024"),
3507
+ temperature: parseFloat(process.env.OPENAI_TEMPERATURE || "0.7")
3508
+ };
3509
+ }
3510
+ if (process.env.ANTHROPIC_API_KEY) {
3511
+ return {
3512
+ provider: "anthropic",
3513
+ model: process.env.ANTHROPIC_MODEL || "claude-3-haiku-20240307",
3514
+ apiKey: process.env.ANTHROPIC_API_KEY,
3515
+ maxTokens: parseInt(process.env.ANTHROPIC_MAX_TOKENS || "1024"),
3516
+ temperature: parseFloat(process.env.ANTHROPIC_TEMPERATURE || "0.7")
3517
+ };
3518
+ }
3519
+ if (process.env.OLLAMA_BASE_URL) {
3520
+ return {
3521
+ provider: "ollama",
3522
+ model: process.env.OLLAMA_MODEL || "mistral",
3523
+ baseUrl: process.env.OLLAMA_BASE_URL,
3524
+ maxTokens: parseInt(process.env.OLLAMA_MAX_TOKENS || "1024"),
3525
+ temperature: parseFloat(process.env.OLLAMA_TEMPERATURE || "0.7")
3526
+ };
3527
+ }
3528
+ return {
3529
+ provider: "openai",
3530
+ model: "gpt-4o-mini",
3531
+ apiKey: process.env.OPENAI_API_KEY
3532
+ };
3533
+ }
3534
+ autoDetectEmbedding() {
3535
+ if (process.env.EMBEDDING_PROVIDER) {
3536
+ const provider = process.env.EMBEDDING_PROVIDER;
3537
+ return {
3538
+ provider,
3539
+ model: process.env.EMBEDDING_MODEL || "default",
3540
+ apiKey: process.env.EMBEDDING_API_KEY,
3541
+ baseUrl: process.env.EMBEDDING_BASE_URL
3542
+ };
3543
+ }
3544
+ return {
3545
+ provider: "openai",
3546
+ model: "text-embedding-3-small",
3547
+ apiKey: process.env.OPENAI_API_KEY
3548
+ };
3549
+ }
3550
+ };
3551
+ var PRESETS = {
3552
+ /**
3553
+ * OpenAI + Pinecone: Production-ready cloud setup
3554
+ */
3555
+ "openai-pinecone": {
3556
+ vectorDb: "pinecone",
3557
+ llm: "openai",
3558
+ embedding: "openai"
3559
+ },
3560
+ /**
3561
+ * Claude + Qdrant: Open-source vector DB + proprietary LLM
3562
+ */
3563
+ "claude-qdrant": {
3564
+ vectorDb: "qdrant",
3565
+ llm: "anthropic",
3566
+ embedding: "openai"
3567
+ },
3568
+ /**
3569
+ * Local development: Ollama + local Qdrant
3570
+ */
3571
+ "local-dev": {
3572
+ vectorDb: "qdrant",
3573
+ llm: "ollama",
3574
+ embedding: "ollama"
3575
+ },
3576
+ /**
3577
+ * Fully open-source: Ollama LLM + Qdrant vector DB + Ollama embeddings
3578
+ */
3579
+ "fully-open-source": {
3580
+ vectorDb: "qdrant",
3581
+ llm: "ollama",
3582
+ embedding: "ollama"
3583
+ },
3584
+ /**
3585
+ * PostgreSQL stack: pgvector + OpenAI
3586
+ */
3587
+ "postgres-openai": {
3588
+ vectorDb: "postgresql",
3589
+ llm: "openai",
3590
+ embedding: "openai"
3591
+ },
3592
+ /**
3593
+ * Enterprise MongoDB: MongoDB Atlas with OpenAI
3594
+ */
3595
+ "mongodb-openai": {
3596
+ vectorDb: "mongodb",
3597
+ llm: "openai",
3598
+ embedding: "openai"
3599
+ },
3600
+ /**
3601
+ * Redis stack for caching + search
3602
+ */
3603
+ "redis-openai": {
3604
+ vectorDb: "redis",
3605
+ llm: "openai",
3606
+ embedding: "openai"
3607
+ }
3608
+ };
3609
+ function createFromPreset(presetName) {
3610
+ const preset = PRESETS[presetName];
3611
+ 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`]);
3612
+ }
3035
3613
 
3036
3614
  // src/utils/DocumentParser.ts
3037
3615
  var DocumentParser = class {
@@ -3092,7 +3670,133 @@ var DocumentParser = class {
3092
3670
  }
3093
3671
  };
3094
3672
 
3673
+ // src/server.ts
3674
+ init_BaseVectorProvider();
3675
+ init_PineconeProvider();
3676
+ init_PostgreSQLProvider();
3677
+
3678
+ // src/providers/vectordb/MultiTablePostgresProvider.ts
3679
+ var import_pg2 = require("pg");
3680
+ init_BaseVectorProvider();
3681
+ var MultiTablePostgresProvider = class extends BaseVectorProvider {
3682
+ constructor(config) {
3683
+ var _a, _b, _c;
3684
+ super(config);
3685
+ const opts = config.options || {};
3686
+ if (!opts.connectionString) {
3687
+ throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
3688
+ }
3689
+ this.connectionString = opts.connectionString;
3690
+ this.dimensions = (_a = opts.dimensions) != null ? _a : 768;
3691
+ const rawTables = (_c = (_b = opts.tables) != null ? _b : process.env.VECTOR_DB_TABLES) != null ? _c : "";
3692
+ this.tables = typeof rawTables === "string" ? rawTables.split(",").map((t) => t.trim()).filter(Boolean) : rawTables;
3693
+ if (this.tables.length === 0) {
3694
+ console.warn(
3695
+ "[MultiTablePostgresProvider] No tables configured. Set VECTOR_DB_TABLES as a comma-separated list of table names or pass options.tables."
3696
+ );
3697
+ }
3698
+ }
3699
+ async initialize() {
3700
+ this.pool = new import_pg2.Pool({ connectionString: this.connectionString });
3701
+ const client = await this.pool.connect();
3702
+ client.release();
3703
+ console.log(
3704
+ `[MultiTablePostgresProvider] Connected. Searching across ${this.tables.length} table(s): ${this.tables.join(", ")}`
3705
+ );
3706
+ }
3707
+ /**
3708
+ * Upsert is not supported for MultiTablePostgresProvider as it's designed for
3709
+ * searching across pre-existing tables with varying schemas.
3710
+ */
3711
+ async upsert(_doc, _namespace) {
3712
+ throw new Error(
3713
+ "[MultiTablePostgresProvider] upsert() is not supported in multi-table mode. Please use the standard PostgreSQLProvider for single-table managed indices."
3714
+ );
3715
+ }
3716
+ /**
3717
+ * Batch upsert is not supported for MultiTablePostgresProvider.
3718
+ */
3719
+ async batchUpsert(_docs, _namespace) {
3720
+ throw new Error(
3721
+ "[MultiTablePostgresProvider] batchUpsert() is not supported in multi-table mode."
3722
+ );
3723
+ }
3724
+ /**
3725
+ * Query all configured tables and merge results, sorted by cosine similarity score.
3726
+ */
3727
+ async query(vector, topK, _namespace, _filter) {
3728
+ var _b, _c;
3729
+ if (!this.pool) {
3730
+ throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
3731
+ }
3732
+ console.log(`[MultiTablePostgresProvider] Querying ${this.tables.length} table(s) with vector dim=${vector.length}`);
3733
+ const vectorLiteral = `[${vector.join(",")}]`;
3734
+ const allResults = [];
3735
+ for (const table of this.tables) {
3736
+ try {
3737
+ const result = await this.pool.query(
3738
+ `SELECT *, 1 - (embedding <=> $1::vector) AS score
3739
+ FROM "${table}"
3740
+ ORDER BY embedding <=> $1::vector
3741
+ LIMIT $2`,
3742
+ [vectorLiteral, topK]
3743
+ );
3744
+ for (const row of result.rows) {
3745
+ const _a = row, { score, id } = _a, rest = __objRest(_a, ["score", "id"]);
3746
+ delete rest.embedding;
3747
+ const content = Object.entries(rest).filter(([k, v]) => v !== null && typeof v !== "object" && k !== "id").map(([k, v]) => `${k}: ${v}`).join("\n");
3748
+ allResults.push({
3749
+ id: `${table}-${id}`,
3750
+ score: parseFloat(String(score)),
3751
+ content,
3752
+ metadata: __spreadProps(__spreadValues({}, rest), { source_table: table })
3753
+ });
3754
+ }
3755
+ } catch (err) {
3756
+ console.error(
3757
+ `[MultiTablePostgresProvider] Error querying table "${table}":`,
3758
+ err.message
3759
+ );
3760
+ }
3761
+ }
3762
+ const sortedResults = allResults.sort((a, b) => b.score - a.score);
3763
+ if (sortedResults.length > 0) {
3764
+ console.log(`[MultiTablePostgresProvider] Top match from "${(_c = (_b = sortedResults[0].metadata) == null ? void 0 : _b.source_table) != null ? _c : "unknown"}" with score ${sortedResults[0].score.toFixed(4)}`);
3765
+ }
3766
+ return sortedResults.slice(0, topK);
3767
+ }
3768
+ async delete(_id, _namespace) {
3769
+ console.warn("[MultiTablePostgresProvider] delete() is a no-op for multi-table mode.");
3770
+ }
3771
+ async deleteNamespace(_namespace) {
3772
+ console.warn("[MultiTablePostgresProvider] deleteNamespace() is a no-op for multi-table mode.");
3773
+ }
3774
+ async ping() {
3775
+ try {
3776
+ await this.pool.query("SELECT 1");
3777
+ return true;
3778
+ } catch (e) {
3779
+ return false;
3780
+ }
3781
+ }
3782
+ async disconnect() {
3783
+ if (this.pool) {
3784
+ await this.pool.end();
3785
+ }
3786
+ }
3787
+ };
3788
+
3789
+ // src/server.ts
3790
+ init_MongoDBProvider();
3791
+ init_MilvusProvider();
3792
+ init_QdrantProvider();
3793
+ init_ChromaDBProvider();
3794
+ init_RedisProvider();
3795
+ init_WeaviateProvider();
3796
+ init_UniversalVectorProvider();
3797
+
3095
3798
  // src/handlers/index.ts
3799
+ var import_server = require("next/server");
3096
3800
  function createChatHandler(config) {
3097
3801
  const plugin = new VectorPlugin(config);
3098
3802
  return async function POST(req) {
@@ -3181,23 +3885,37 @@ function createUploadHandler(config) {
3181
3885
  0 && (module.exports = {
3182
3886
  AnthropicProvider,
3183
3887
  BaseVectorProvider,
3888
+ BatchProcessor,
3184
3889
  ChromaDBProvider,
3890
+ ConfigBuilder,
3185
3891
  ConfigResolver,
3892
+ ConfigValidator,
3186
3893
  DocumentChunker,
3894
+ DocumentParser,
3895
+ EmbeddingStrategy,
3896
+ EmbeddingStrategyResolver,
3187
3897
  LLMFactory,
3898
+ LLM_PROFILES,
3188
3899
  MilvusProvider,
3189
3900
  MongoDBProvider,
3901
+ MultiTablePostgresProvider,
3190
3902
  OllamaProvider,
3191
3903
  OpenAIProvider,
3904
+ PRESETS,
3192
3905
  PineconeProvider,
3193
3906
  Pipeline,
3194
3907
  PostgreSQLProvider,
3908
+ ProviderHealthCheck,
3195
3909
  ProviderRegistry,
3196
3910
  QdrantProvider,
3197
3911
  RedisProvider,
3912
+ UniversalLLMAdapter,
3913
+ UniversalVectorProvider,
3914
+ VECTOR_PROFILES,
3198
3915
  VectorPlugin,
3199
3916
  WeaviateProvider,
3200
3917
  createChatHandler,
3918
+ createFromPreset,
3201
3919
  createHealthHandler,
3202
3920
  createIngestHandler,
3203
3921
  createUploadHandler,