@retrivora-ai/rag-engine 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/{ChromaDBProvider-QNI7UCX4.mjs → ChromaDBProvider-2JZSBOQX.mjs} +1 -1
  2. package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-CJDBCBVI.mjs} +1 -1
  3. package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-E6L5Z2FO.mjs} +1 -1
  4. package/dist/{QdrantProvider-VAED5VA7.mjs → QdrantProvider-JITRNJQN.mjs} +1 -1
  5. package/dist/{RagConfig-hBGXJmSx.d.mts → RagConfig-D_rSf8ep.d.mts} +1 -1
  6. package/dist/{RagConfig-hBGXJmSx.d.ts → RagConfig-D_rSf8ep.d.ts} +1 -1
  7. package/dist/{RedisProvider-ASONNYBI.mjs → RedisProvider-3VKFQXXD.mjs} +1 -1
  8. package/dist/UniversalVectorProvider-E6L4U4OX.mjs +9 -0
  9. package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-MXIPP44J.mjs} +1 -1
  10. package/dist/{chunk-CWQQHAF6.mjs → chunk-26EMHLIN.mjs} +3 -5
  11. package/dist/{chunk-VPNRDXIA.mjs → chunk-7BQI4A5J.mjs} +17 -11
  12. package/dist/{chunk-ZM6TYIDH.mjs → chunk-MFWJZVF3.mjs} +3 -1
  13. package/dist/{chunk-V75V7BT2.mjs → chunk-TSX6DQXX.mjs} +2 -2
  14. package/dist/{chunk-HUGLYKD6.mjs → chunk-XZPVJS2B.mjs} +27 -9
  15. package/dist/chunk-Y6HQZDCJ.mjs +156 -0
  16. package/dist/{chunk-7YQWGERZ.mjs → chunk-YIYDJQJM.mjs} +736 -189
  17. package/dist/{chunk-7NXI6ZWX.mjs → chunk-YST6KYBJ.mjs} +8 -5
  18. package/dist/handlers/index.d.mts +2 -2
  19. package/dist/handlers/index.d.ts +2 -2
  20. package/dist/handlers/index.js +877 -625
  21. package/dist/handlers/index.mjs +1 -2
  22. package/dist/index-BJ8CUArE.d.mts +114 -0
  23. package/dist/index-DtNprGGj.d.ts +114 -0
  24. package/dist/index.d.mts +2 -2
  25. package/dist/index.d.ts +2 -2
  26. package/dist/server.d.mts +566 -17
  27. package/dist/server.d.ts +566 -17
  28. package/dist/server.js +1233 -642
  29. package/dist/server.mjs +314 -16
  30. package/package.json +11 -2
  31. package/src/config/ConfigBuilder.ts +373 -0
  32. package/src/config/EmbeddingStrategy.ts +147 -0
  33. package/src/config/serverConfig.ts +51 -18
  34. package/src/core/ConfigValidator.ts +67 -50
  35. package/src/core/Pipeline.ts +28 -26
  36. package/src/core/PluginManager.ts +277 -0
  37. package/src/core/ProviderHealthCheck.ts +75 -139
  38. package/src/core/ProviderRegistry.ts +38 -15
  39. package/src/providers/vectordb/ChromaDBProvider.ts +37 -12
  40. package/src/providers/vectordb/MilvusProvider.ts +25 -10
  41. package/src/providers/vectordb/PineconeProvider.ts +17 -2
  42. package/src/providers/vectordb/QdrantProvider.ts +3 -6
  43. package/src/providers/vectordb/RedisProvider.ts +34 -11
  44. package/src/providers/vectordb/UniversalVectorProvider.ts +220 -0
  45. package/src/providers/vectordb/WeaviateProvider.ts +17 -10
  46. package/src/server.ts +28 -10
  47. package/dist/LLMFactory-JFOY2V4X.mjs +0 -8
  48. package/dist/chunk-JI6VD5TJ.mjs +0 -387
  49. package/dist/index-Bx182KKn.d.ts +0 -64
  50. package/dist/index-Ck2pt7-8.d.mts +0 -64
  51. package/src/test-refactor.ts +0 -59
@@ -1,8 +1,7 @@
1
1
  import {
2
- LLMFactory
3
- } from "./chunk-JI6VD5TJ.mjs";
4
- import {
5
- mergeDefined
2
+ buildPayload,
3
+ mergeDefined,
4
+ resolvePath
6
5
  } from "./chunk-UKDXCXW7.mjs";
7
6
  import {
8
7
  __spreadProps,
@@ -13,7 +12,20 @@ import {
13
12
  import { NextResponse } from "next/server";
14
13
 
15
14
  // src/config/serverConfig.ts
16
- var VECTOR_DB_PROVIDERS = ["pinecone", "pgvector", "postgresql", "mongodb", "milvus", "qdrant", "chromadb", "redis", "weaviate", "rest", "universal_rest", "custom"];
15
+ var VECTOR_DB_PROVIDERS = [
16
+ "pinecone",
17
+ "pgvector",
18
+ "postgresql",
19
+ "mongodb",
20
+ "milvus",
21
+ "qdrant",
22
+ "chromadb",
23
+ "redis",
24
+ "weaviate",
25
+ "rest",
26
+ "universal_rest",
27
+ "custom"
28
+ ];
17
29
  var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
18
30
  var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
19
31
  function readString(env, name) {
@@ -39,7 +51,7 @@ function readEnum(env, name, fallback, allowed) {
39
51
  throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
40
52
  }
41
53
  function getRagConfig(env = process.env) {
42
- 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;
54
+ 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;
43
55
  const projectId = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : "__default__";
44
56
  const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
45
57
  const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
@@ -48,49 +60,62 @@ function getRagConfig(env = process.env) {
48
60
  const vectorDbOptions = {};
49
61
  if (vectorProvider === "pinecone") {
50
62
  vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
51
- vectorDbOptions.environment = (_d = readString(env, "PINECONE_ENVIRONMENT")) != null ? _d : "";
52
- } else if (vectorProvider === "pgvector") {
53
- vectorDbOptions.connectionString = (_e = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _e : "";
63
+ } else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
64
+ vectorDbOptions.connectionString = (_d = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _d : "";
65
+ vectorDbOptions.dimensions = embeddingDimensions;
66
+ } else if (vectorProvider === "mongodb") {
67
+ vectorDbOptions.uri = (_e = readString(env, "MONGODB_URI")) != null ? _e : "";
68
+ vectorDbOptions.database = (_f = readString(env, "MONGODB_DB")) != null ? _f : "";
69
+ vectorDbOptions.collection = (_g = readString(env, "MONGODB_COLLECTION")) != null ? _g : "";
70
+ vectorDbOptions.indexName = (_h = readString(env, "MONGODB_INDEX_NAME")) != null ? _h : "vector_index";
71
+ } else if (vectorProvider === "qdrant") {
72
+ vectorDbOptions.baseUrl = (_i = readString(env, "QDRANT_URL")) != null ? _i : "http://localhost:6333";
73
+ vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
54
74
  vectorDbOptions.dimensions = embeddingDimensions;
75
+ } else if (vectorProvider === "milvus") {
76
+ vectorDbOptions.baseUrl = (_j = readString(env, "MILVUS_URL")) != null ? _j : "http://localhost:19530";
77
+ vectorDbOptions.apiKey = readString(env, "MILVUS_API_KEY");
78
+ } else if (vectorProvider === "chromadb") {
79
+ vectorDbOptions.baseUrl = (_k = readString(env, "CHROMADB_URL")) != null ? _k : "http://localhost:8000";
80
+ } else if (vectorProvider === "weaviate") {
81
+ vectorDbOptions.baseUrl = (_l = readString(env, "WEAVIATE_URL")) != null ? _l : "http://localhost:8080";
82
+ vectorDbOptions.apiKey = readString(env, "WEAVIATE_API_KEY");
83
+ } else if (vectorProvider === "redis") {
84
+ vectorDbOptions.baseUrl = (_m = readString(env, "REDIS_URL")) != null ? _m : "";
85
+ vectorDbOptions.apiKey = readString(env, "REDIS_API_KEY");
55
86
  } else if (vectorProvider === "rest") {
56
- vectorDbOptions.baseUrl = (_f = readString(env, "VECTOR_DB_REST_URL")) != null ? _f : "";
87
+ vectorDbOptions.baseUrl = (_n = readString(env, "VECTOR_DB_REST_URL")) != null ? _n : "";
57
88
  vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { "api-key": readString(env, "VECTOR_DB_REST_API_KEY") } : {};
58
89
  } else if (vectorProvider === "universal_rest") {
59
- vectorDbOptions.baseUrl = (_h = (_g = readString(env, "VECTOR_BASE_URL")) != null ? _g : readString(env, "VECTOR_DB_REST_URL")) != null ? _h : "";
90
+ vectorDbOptions.baseUrl = (_p = (_o = readString(env, "VECTOR_BASE_URL")) != null ? _o : readString(env, "VECTOR_DB_REST_URL")) != null ? _p : "";
60
91
  vectorDbOptions.profile = readString(env, "VECTOR_UNIVERSAL_PROFILE");
61
92
  vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { Authorization: `Bearer ${readString(env, "VECTOR_DB_REST_API_KEY")}` } : {};
62
- } else if (vectorProvider === "mongodb") {
63
- vectorDbOptions.uri = (_i = readString(env, "MONGODB_URI")) != null ? _i : "";
64
- vectorDbOptions.database = (_j = readString(env, "MONGODB_DB")) != null ? _j : "";
65
- vectorDbOptions.collection = (_k = readString(env, "MONGODB_COLLECTION")) != null ? _k : "";
66
- vectorDbOptions.indexName = (_l = readString(env, "MONGODB_INDEX_NAME")) != null ? _l : "vector_index";
67
- } else if (vectorProvider === "qdrant") {
68
- vectorDbOptions.baseUrl = (_m = readString(env, "QDRANT_URL")) != null ? _m : "http://localhost:6333";
69
- vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
70
- vectorDbOptions.dimensions = embeddingDimensions;
71
93
  }
72
94
  const llmApiKeyByProvider = {
73
95
  openai: readString(env, "OPENAI_API_KEY"),
74
96
  anthropic: readString(env, "ANTHROPIC_API_KEY"),
75
97
  ollama: void 0,
76
- universal_rest: readString(env, "LLM_API_KEY")
98
+ universal_rest: readString(env, "LLM_API_KEY"),
99
+ rest: readString(env, "LLM_API_KEY"),
100
+ custom: readString(env, "LLM_API_KEY")
77
101
  };
78
102
  const embeddingApiKeyByProvider = {
79
103
  openai: readString(env, "OPENAI_API_KEY"),
80
104
  ollama: void 0,
81
- custom: (_n = readString(env, "EMBEDDING_API_KEY")) != null ? _n : readString(env, "OPENAI_API_KEY")
105
+ universal_rest: (_q = readString(env, "EMBEDDING_API_KEY")) != null ? _q : readString(env, "OPENAI_API_KEY"),
106
+ custom: (_r = readString(env, "EMBEDDING_API_KEY")) != null ? _r : readString(env, "OPENAI_API_KEY")
82
107
  };
83
108
  return {
84
109
  projectId,
85
110
  vectorDb: {
86
111
  provider: vectorProvider,
87
- indexName: (_o = readString(env, "VECTOR_DB_INDEX")) != null ? _o : "rag-index",
112
+ indexName: (_s = readString(env, "VECTOR_DB_INDEX")) != null ? _s : "rag-index",
88
113
  options: vectorDbOptions
89
114
  },
90
115
  llm: {
91
116
  provider: llmProvider,
92
- model: (_p = readString(env, "LLM_MODEL")) != null ? _p : "gpt-4o",
93
- apiKey: (_q = llmApiKeyByProvider[llmProvider]) != null ? _q : "",
117
+ model: (_t = readString(env, "LLM_MODEL")) != null ? _t : "gpt-4o",
118
+ apiKey: (_u = llmApiKeyByProvider[llmProvider]) != null ? _u : "",
94
119
  baseUrl: readString(env, "LLM_BASE_URL"),
95
120
  systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
96
121
  maxTokens: readNumber(env, "LLM_MAX_TOKENS", 1024),
@@ -101,7 +126,7 @@ function getRagConfig(env = process.env) {
101
126
  },
102
127
  embedding: {
103
128
  provider: embeddingProvider,
104
- model: (_r = readString(env, "EMBEDDING_MODEL")) != null ? _r : "text-embedding-3-small",
129
+ model: (_v = readString(env, "EMBEDDING_MODEL")) != null ? _v : "text-embedding-3-small",
105
130
  apiKey: embeddingApiKeyByProvider[embeddingProvider],
106
131
  baseUrl: readString(env, "EMBEDDING_BASE_URL"),
107
132
  dimensions: embeddingDimensions,
@@ -110,16 +135,16 @@ function getRagConfig(env = process.env) {
110
135
  }
111
136
  },
112
137
  ui: {
113
- title: (_t = (_s = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _s : readString(env, "UI_TITLE")) != null ? _t : "AI Assistant",
114
- subtitle: (_v = (_u = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _u : readString(env, "UI_SUBTITLE")) != null ? _v : "Powered by RAG",
115
- primaryColor: (_x = (_w = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _w : readString(env, "UI_PRIMARY_COLOR")) != null ? _x : "#10b981",
116
- accentColor: (_z = (_y = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _y : readString(env, "UI_ACCENT_COLOR")) != null ? _z : "#3b82f6",
117
- logoUrl: (_A = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _A : readString(env, "UI_LOGO_URL"),
118
- placeholder: (_C = (_B = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _B : readString(env, "UI_PLACEHOLDER")) != null ? _C : "Ask me anything\u2026",
119
- showSources: ((_E = (_D = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _D : readString(env, "UI_SHOW_SOURCES")) != null ? _E : "true") !== "false",
120
- 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.",
121
- visualStyle: (_I = (_H = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _H : readString(env, "UI_VISUAL_STYLE")) != null ? _I : "glass",
122
- borderRadius: (_K = (_J = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _J : readString(env, "UI_BORDER_RADIUS")) != null ? _K : "xl"
138
+ title: (_x = (_w = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _w : readString(env, "UI_TITLE")) != null ? _x : "AI Assistant",
139
+ subtitle: (_z = (_y = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _y : readString(env, "UI_SUBTITLE")) != null ? _z : "Powered by RAG",
140
+ primaryColor: (_B = (_A = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _A : readString(env, "UI_PRIMARY_COLOR")) != null ? _B : "#10b981",
141
+ accentColor: (_D = (_C = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _C : readString(env, "UI_ACCENT_COLOR")) != null ? _D : "#3b82f6",
142
+ logoUrl: (_E = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _E : readString(env, "UI_LOGO_URL"),
143
+ placeholder: (_G = (_F = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _F : readString(env, "UI_PLACEHOLDER")) != null ? _G : "Ask me anything\u2026",
144
+ showSources: ((_I = (_H = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _H : readString(env, "UI_SHOW_SOURCES")) != null ? _I : "true") !== "false",
145
+ 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.",
146
+ visualStyle: (_M = (_L = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _L : readString(env, "UI_VISUAL_STYLE")) != null ? _M : "glass",
147
+ borderRadius: (_O = (_N = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _N : readString(env, "UI_BORDER_RADIUS")) != null ? _O : "xl"
123
148
  },
124
149
  rag: {
125
150
  topK: readNumber(env, "RAG_TOP_K", 5),
@@ -195,7 +220,7 @@ var ConfigValidator = class {
195
220
  errors.push({
196
221
  field: "embedding",
197
222
  message: "Embedding config is required when using Anthropic LLM",
198
- suggestion: 'Provide embedding config with provider (e.g., "openai")',
223
+ suggestion: 'Provide embedding config with provider (e.g., "openai" or "ollama")',
199
224
  severity: "error"
200
225
  });
201
226
  }
@@ -257,6 +282,10 @@ var ConfigValidator = class {
257
282
  }
258
283
  return errors;
259
284
  }
285
+ /**
286
+ * Pinecone — only needs apiKey (environment was removed in SDK v7+).
287
+ * Options key: { apiKey: string }
288
+ */
260
289
  static validatePineconeConfig(config) {
261
290
  const errors = [];
262
291
  const opts = config.options;
@@ -268,16 +297,12 @@ var ConfigValidator = class {
268
297
  severity: "error"
269
298
  });
270
299
  }
271
- if (!opts.environment) {
272
- errors.push({
273
- field: "vectorDb.options.environment",
274
- message: "Pinecone environment is required",
275
- suggestion: 'Set PINECONE_ENVIRONMENT environment variable (e.g., "gcp-starter")',
276
- severity: "error"
277
- });
278
- }
279
300
  return errors;
280
301
  }
302
+ /**
303
+ * PostgreSQL / pgvector — needs a connection string.
304
+ * Options key: { connectionString: string }
305
+ */
281
306
  static validatePostgresConfig(config) {
282
307
  const errors = [];
283
308
  const opts = config.options;
@@ -291,6 +316,10 @@ var ConfigValidator = class {
291
316
  }
292
317
  return errors;
293
318
  }
319
+ /**
320
+ * MongoDB — needs uri, database, and collection.
321
+ * Options keys: { uri: string, database: string, collection: string }
322
+ */
294
323
  static validateMongoDBConfig(config) {
295
324
  const errors = [];
296
325
  const opts = config.options;
@@ -320,27 +349,30 @@ var ConfigValidator = class {
320
349
  }
321
350
  return errors;
322
351
  }
352
+ /**
353
+ * Milvus — accepts baseUrl OR uri (preferred) OR host+port.
354
+ * MilvusProvider reads opts.baseUrl ?? opts.uri.
355
+ * Options keys: { baseUrl?: string, uri?: string, host?: string, port?: number }
356
+ */
323
357
  static validateMilvusConfig(config) {
324
358
  const errors = [];
325
359
  const opts = config.options;
326
- if (!opts.host) {
327
- errors.push({
328
- field: "vectorDb.options.host",
329
- message: "Milvus host is required",
330
- suggestion: "Set MILVUS_HOST environment variable",
331
- severity: "error"
332
- });
333
- }
334
- if (!opts.port) {
360
+ const hasBaseUrl = Boolean(opts.baseUrl || opts.uri);
361
+ const hasHostPort = Boolean(opts.host && opts.port);
362
+ if (!hasBaseUrl && !hasHostPort) {
335
363
  errors.push({
336
- field: "vectorDb.options.port",
337
- message: "Milvus port is required",
338
- suggestion: "Set MILVUS_PORT environment variable (default: 19530)",
364
+ field: "vectorDb.options.baseUrl",
365
+ message: 'Milvus connection is required: provide baseUrl (e.g., "http://localhost:19530") or host + port',
366
+ suggestion: "Set MILVUS_URL environment variable",
339
367
  severity: "error"
340
368
  });
341
369
  }
342
370
  return errors;
343
371
  }
372
+ /**
373
+ * Qdrant — needs baseUrl (or url alias).
374
+ * Options keys: { baseUrl: string, apiKey?: string }
375
+ */
344
376
  static validateQdrantConfig(config) {
345
377
  const errors = [];
346
378
  const opts = config.options;
@@ -354,38 +386,55 @@ var ConfigValidator = class {
354
386
  }
355
387
  return errors;
356
388
  }
389
+ /**
390
+ * ChromaDB — accepts baseUrl OR host.
391
+ * ChromaDBProvider reads opts.baseUrl.
392
+ * Options keys: { baseUrl?: string, host?: string, port?: number }
393
+ */
357
394
  static validateChromaDBConfig(config) {
358
395
  const errors = [];
359
396
  const opts = config.options;
360
- if (!opts.host && !opts.path) {
397
+ if (!opts.baseUrl && !opts.host) {
361
398
  errors.push({
362
- field: "vectorDb.options.host",
363
- message: "ChromaDB host or path is required",
364
- suggestion: "Set CHROMADB_HOST or CHROMADB_PATH environment variable",
399
+ field: "vectorDb.options.baseUrl",
400
+ message: 'ChromaDB connection is required: provide baseUrl (e.g., "http://localhost:8000") or host',
401
+ suggestion: "Set CHROMADB_URL environment variable",
365
402
  severity: "error"
366
403
  });
367
404
  }
368
405
  return errors;
369
406
  }
407
+ /**
408
+ * Redis — accepts baseUrl OR url OR host+port.
409
+ * RedisProvider reads opts.baseUrl.
410
+ * Options keys: { baseUrl?: string, url?: string, host?: string, port?: number, apiKey?: string }
411
+ */
370
412
  static validateRedisConfig(config) {
371
413
  const errors = [];
372
414
  const opts = config.options;
373
- if (!opts.url && (!opts.host || !opts.port)) {
415
+ const hasUrl = Boolean(opts.baseUrl || opts.url);
416
+ const hasHostPort = Boolean(opts.host && opts.port);
417
+ if (!hasUrl && !hasHostPort) {
374
418
  errors.push({
375
- field: "vectorDb.options.url",
376
- message: "Redis connection URL or host:port is required",
377
- suggestion: "Set REDIS_URL or REDIS_HOST/REDIS_PORT environment variables",
419
+ field: "vectorDb.options.baseUrl",
420
+ message: "Redis connection is required: provide baseUrl/url or host + port",
421
+ suggestion: "Set REDIS_URL environment variable",
378
422
  severity: "error"
379
423
  });
380
424
  }
381
425
  return errors;
382
426
  }
427
+ /**
428
+ * Weaviate — accepts baseUrl OR url.
429
+ * WeaviateProvider reads opts.baseUrl.
430
+ * Options keys: { baseUrl?: string, url?: string, apiKey?: string }
431
+ */
383
432
  static validateWeaviateConfig(config) {
384
433
  const errors = [];
385
434
  const opts = config.options;
386
- if (!opts.url) {
435
+ if (!opts.baseUrl && !opts.url) {
387
436
  errors.push({
388
- field: "vectorDb.options.url",
437
+ field: "vectorDb.options.baseUrl",
389
438
  message: "Weaviate instance URL is required",
390
439
  suggestion: "Set WEAVIATE_URL environment variable",
391
440
  severity: "error"
@@ -393,6 +442,10 @@ var ConfigValidator = class {
393
442
  }
394
443
  return errors;
395
444
  }
445
+ /**
446
+ * Universal REST / custom REST adapter.
447
+ * Options key: { baseUrl: string }
448
+ */
396
449
  static validateRestConfig(config) {
397
450
  const errors = [];
398
451
  const opts = config.options;
@@ -500,7 +553,7 @@ var ConfigValidator = class {
500
553
  errors.push({
501
554
  field: "embedding.model",
502
555
  message: "Embedding model name is required",
503
- suggestion: 'e.g., "text-embedding-3-small" for OpenAI',
556
+ suggestion: 'e.g., "text-embedding-3-small" for OpenAI, "nomic-embed-text" for Ollama',
504
557
  severity: "error"
505
558
  });
506
559
  }
@@ -515,7 +568,7 @@ var ConfigValidator = class {
515
568
  if (config.provider === "ollama" && !config.baseUrl) {
516
569
  errors.push({
517
570
  field: "embedding.baseUrl",
518
- message: "Ollama base URL is required",
571
+ message: "Ollama base URL is required for embedding",
519
572
  suggestion: "Set EMBEDDING_BASE_URL environment variable",
520
573
  severity: "error"
521
574
  });
@@ -692,16 +745,432 @@ var DocumentChunker = class {
692
745
  }
693
746
  };
694
747
 
748
+ // src/llm/providers/OpenAIProvider.ts
749
+ import OpenAI from "openai";
750
+ var OpenAIProvider = class {
751
+ constructor(llmConfig, embeddingConfig) {
752
+ if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
753
+ this.client = new OpenAI({ apiKey: llmConfig.apiKey });
754
+ this.llmConfig = llmConfig;
755
+ this.embeddingConfig = embeddingConfig;
756
+ }
757
+ async chat(messages, context, options) {
758
+ var _a, _b, _c, _d, _e, _f, _g, _h;
759
+ const systemContent = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
760
+
761
+ Context:
762
+ ${context}`;
763
+ const systemMessage = {
764
+ role: "system",
765
+ content: systemContent.includes("{{context}}") ? systemContent.replace("{{context}}", context) : `${systemContent}
766
+
767
+ Context:
768
+ ${context}`
769
+ };
770
+ const formattedMessages = [
771
+ systemMessage,
772
+ ...messages.map((m) => ({
773
+ role: m.role,
774
+ content: m.content
775
+ }))
776
+ ];
777
+ const completion = await this.client.chat.completions.create({
778
+ model: this.llmConfig.model,
779
+ messages: formattedMessages,
780
+ max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
781
+ temperature: (_e = (_d = options == null ? void 0 : options.temperature) != null ? _d : this.llmConfig.temperature) != null ? _e : 0.7,
782
+ stop: options == null ? void 0 : options.stop
783
+ });
784
+ return (_h = (_g = (_f = completion.choices[0]) == null ? void 0 : _f.message) == null ? void 0 : _g.content) != null ? _h : "";
785
+ }
786
+ async embed(text, options) {
787
+ const results = await this.batchEmbed([text], options);
788
+ return results[0];
789
+ }
790
+ async batchEmbed(texts, options) {
791
+ var _a, _b, _c, _d, _e;
792
+ 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";
793
+ const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
794
+ const client = apiKey !== this.llmConfig.apiKey ? new OpenAI({ apiKey }) : this.client;
795
+ const response = await client.embeddings.create({ model, input: texts });
796
+ return response.data.map((d) => d.embedding);
797
+ }
798
+ async ping() {
799
+ try {
800
+ await this.client.models.list();
801
+ return true;
802
+ } catch (err) {
803
+ console.error("[OpenAIProvider] Ping failed:", err);
804
+ return false;
805
+ }
806
+ }
807
+ };
808
+
809
+ // src/llm/providers/AnthropicProvider.ts
810
+ import Anthropic from "@anthropic-ai/sdk";
811
+ var AnthropicProvider = class {
812
+ constructor(llmConfig, embeddingConfig) {
813
+ if (!llmConfig.apiKey) throw new Error("[AnthropicProvider] llmConfig.apiKey is required");
814
+ this.client = new Anthropic({ apiKey: llmConfig.apiKey });
815
+ this.llmConfig = llmConfig;
816
+ this.embeddingConfig = embeddingConfig;
817
+ }
818
+ async chat(messages, context, options) {
819
+ var _a, _b, _c;
820
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the context below to answer the user's question accurately.
821
+
822
+ Context:
823
+ ${context}`;
824
+ const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
825
+
826
+ Context:
827
+ ${context}`;
828
+ const anthropicMessages = messages.map((m) => ({
829
+ role: m.role === "assistant" ? "assistant" : "user",
830
+ content: m.content
831
+ }));
832
+ const response = await this.client.messages.create({
833
+ model: this.llmConfig.model,
834
+ max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
835
+ system,
836
+ messages: anthropicMessages
837
+ });
838
+ const block = response.content[0];
839
+ return block.type === "text" ? block.text : "";
840
+ }
841
+ /**
842
+ * Anthropic does not offer an embedding API.
843
+ * This method throws with a clear error so developers know to configure
844
+ * a separate embedding provider (OpenAI or Ollama).
845
+ */
846
+ async embed(text, options) {
847
+ void text;
848
+ void options;
849
+ throw new Error(
850
+ '[AnthropicProvider] Anthropic does not provide an embedding API. Set embedding.provider to "openai" or "ollama" in your RagConfig.'
851
+ );
852
+ }
853
+ async batchEmbed(texts, options) {
854
+ void texts;
855
+ void options;
856
+ throw new Error(
857
+ "[AnthropicProvider] Anthropic does not provide an embedding API."
858
+ );
859
+ }
860
+ async ping() {
861
+ try {
862
+ await this.client.models.list();
863
+ return true;
864
+ } catch (err) {
865
+ console.error("[AnthropicProvider] Ping failed:", err);
866
+ return false;
867
+ }
868
+ }
869
+ };
870
+
871
+ // src/llm/providers/OllamaProvider.ts
872
+ import axios from "axios";
873
+ var OllamaProvider = class {
874
+ constructor(llmConfig, embeddingConfig) {
875
+ var _a;
876
+ const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
877
+ this.http = axios.create({ baseURL, timeout: 12e4 });
878
+ this.llmConfig = llmConfig;
879
+ this.embeddingConfig = embeddingConfig;
880
+ }
881
+ async chat(messages, context, options) {
882
+ var _a, _b, _c, _d, _e;
883
+ const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
884
+
885
+ Context:
886
+ ${context}`;
887
+ const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
888
+
889
+ Context:
890
+ ${context}`;
891
+ const { data } = await this.http.post("/api/chat", {
892
+ model: this.llmConfig.model,
893
+ stream: false,
894
+ options: {
895
+ temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
896
+ num_predict: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024
897
+ },
898
+ messages: [
899
+ { role: "system", content: system },
900
+ ...messages.map((m) => ({ role: m.role, content: m.content }))
901
+ ]
902
+ });
903
+ return data.message.content;
904
+ }
905
+ async embed(text, options) {
906
+ var _a, _b, _c, _d, _e, _f, _g;
907
+ 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";
908
+ const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
909
+ const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? axios.create({ baseURL, timeout: 6e4 }) : this.http;
910
+ const { data } = await client.post("/api/embeddings", {
911
+ model,
912
+ prompt: text
913
+ });
914
+ return data.embedding;
915
+ }
916
+ async batchEmbed(texts, options) {
917
+ const vectors = [];
918
+ for (const text of texts) {
919
+ vectors.push(await this.embed(text, options));
920
+ }
921
+ return vectors;
922
+ }
923
+ async ping() {
924
+ try {
925
+ await this.http.get("/api/tags");
926
+ return true;
927
+ } catch (err) {
928
+ console.error("[OllamaProvider] Ping failed:", err);
929
+ return false;
930
+ }
931
+ }
932
+ };
933
+
934
+ // src/llm/providers/UniversalLLMAdapter.ts
935
+ import axios2 from "axios";
936
+
937
+ // src/config/UniversalProfiles.ts
938
+ var OPENAI_BASE = {
939
+ chatPath: "/chat/completions",
940
+ embedPath: "/embeddings",
941
+ responseExtractPath: "choices[0].message.content",
942
+ embedExtractPath: "data[0].embedding",
943
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
944
+ };
945
+ var LLM_PROFILES = {
946
+ "openai-compatible": OPENAI_BASE,
947
+ "litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
948
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
949
+ }),
950
+ "anthropic-claude": {
951
+ chatPath: "/v1/messages",
952
+ responseExtractPath: "content[0].text",
953
+ headers: { "anthropic-version": "2023-06-01" },
954
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
955
+ },
956
+ "google-gemini": {
957
+ chatPath: "/v1beta/models/{{model}}:generateContent",
958
+ responseExtractPath: "candidates[0].content.parts[0].text",
959
+ chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
960
+ },
961
+ "github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
962
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
963
+ }),
964
+ "ollama-standard": {
965
+ chatPath: "/api/chat",
966
+ embedPath: "/api/embeddings",
967
+ responseExtractPath: "message.content",
968
+ embedExtractPath: "embedding",
969
+ chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
970
+ embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
971
+ }
972
+ };
973
+ var VECTOR_PROFILES = {
974
+ "pinecone-rest": {
975
+ queryPath: "/query",
976
+ upsertPath: "/vectors/upsert",
977
+ responseExtractPath: "matches",
978
+ idPath: "id",
979
+ scorePath: "score",
980
+ contentPath: "metadata.content",
981
+ metadataPath: "metadata",
982
+ queryPayloadTemplate: '{"vector":{{vector}},"topK":{{topK}},"includeMetadata":true,"namespace":"{{namespace}}"}'
983
+ },
984
+ "mongodb-atlas": {
985
+ queryPath: "/action/aggregate",
986
+ responseExtractPath: "documents",
987
+ idPath: "_id",
988
+ scorePath: "score",
989
+ contentPath: "content",
990
+ metadataPath: "metadata",
991
+ 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"}}}]}'
992
+ },
993
+ "chromadb": {
994
+ queryPath: "/api/v1/collections/{{index}}/query",
995
+ upsertPath: "/api/v1/collections/{{index}}/add",
996
+ responseExtractPath: "matches",
997
+ idPath: "id",
998
+ scorePath: "distance",
999
+ contentPath: "document",
1000
+ metadataPath: "metadata"
1001
+ },
1002
+ "qdrant": {
1003
+ queryPath: "/collections/{{index}}/points/search",
1004
+ upsertPath: "/collections/{{index}}/points",
1005
+ responseExtractPath: "result",
1006
+ idPath: "id",
1007
+ scorePath: "score",
1008
+ contentPath: "payload.content",
1009
+ metadataPath: "payload"
1010
+ }
1011
+ };
1012
+
1013
+ // src/llm/providers/UniversalLLMAdapter.ts
1014
+ var UniversalLLMAdapter = class {
1015
+ constructor(config) {
1016
+ var _a, _b, _c, _d, _e, _f, _g;
1017
+ this.model = config.model;
1018
+ const llmConfig = config;
1019
+ const options = (_a = llmConfig.options) != null ? _a : {};
1020
+ let profile = {};
1021
+ if (typeof options.profile === "string") {
1022
+ profile = LLM_PROFILES[options.profile] || {};
1023
+ } else if (typeof options.profile === "object" && options.profile !== null) {
1024
+ profile = options.profile;
1025
+ }
1026
+ this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
1027
+ this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
1028
+ this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
1029
+ this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
1030
+ const baseUrl = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl;
1031
+ if (!baseUrl) {
1032
+ throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
1033
+ }
1034
+ this.http = axios2.create({
1035
+ baseURL: baseUrl,
1036
+ headers: __spreadValues(__spreadValues({
1037
+ "Content-Type": "application/json"
1038
+ }, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {}),
1039
+ timeout: (_g = this.opts.timeout) != null ? _g : 6e4
1040
+ });
1041
+ }
1042
+ async chat(messages, context) {
1043
+ var _a, _b;
1044
+ const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
1045
+ const formattedMessages = [
1046
+ { role: "system", content: `${this.systemPrompt}
1047
+
1048
+ Context:
1049
+ ${context != null ? context : "None"}` },
1050
+ ...messages
1051
+ ];
1052
+ let payload;
1053
+ if (this.opts.chatPayloadTemplate) {
1054
+ payload = buildPayload(this.opts.chatPayloadTemplate, {
1055
+ model: this.model,
1056
+ messages: formattedMessages,
1057
+ maxTokens: this.maxTokens,
1058
+ temperature: this.temperature
1059
+ });
1060
+ } else {
1061
+ payload = {
1062
+ model: this.model,
1063
+ messages: formattedMessages,
1064
+ max_tokens: this.maxTokens,
1065
+ temperature: this.temperature
1066
+ };
1067
+ }
1068
+ const { data } = await this.http.post(path, payload);
1069
+ const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
1070
+ const result = resolvePath(data, extractPath);
1071
+ if (result === void 0) {
1072
+ throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
1073
+ }
1074
+ return String(result);
1075
+ }
1076
+ async embed(text) {
1077
+ var _a, _b;
1078
+ const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
1079
+ let payload;
1080
+ if (this.opts.embedPayloadTemplate) {
1081
+ payload = buildPayload(this.opts.embedPayloadTemplate, {
1082
+ model: this.model,
1083
+ input: text
1084
+ });
1085
+ } else {
1086
+ payload = {
1087
+ model: this.model,
1088
+ input: text
1089
+ };
1090
+ }
1091
+ const { data } = await this.http.post(path, payload);
1092
+ const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
1093
+ const vector = resolvePath(data, extractPath);
1094
+ if (!Array.isArray(vector)) {
1095
+ throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
1096
+ }
1097
+ return vector;
1098
+ }
1099
+ async batchEmbed(texts) {
1100
+ const vectors = [];
1101
+ for (const text of texts) {
1102
+ vectors.push(await this.embed(text));
1103
+ }
1104
+ return vectors;
1105
+ }
1106
+ async ping() {
1107
+ try {
1108
+ if (this.opts.pingPath) {
1109
+ await this.http.get(this.opts.pingPath);
1110
+ }
1111
+ return true;
1112
+ } catch (err) {
1113
+ console.error("[UniversalLLMAdapter] Ping failed:", err);
1114
+ return false;
1115
+ }
1116
+ }
1117
+ };
1118
+
1119
+ // src/llm/LLMFactory.ts
1120
+ var LLMFactory = class _LLMFactory {
1121
+ static create(llmConfig, embeddingConfig) {
1122
+ var _a;
1123
+ switch (llmConfig.provider) {
1124
+ case "openai":
1125
+ return new OpenAIProvider(llmConfig, embeddingConfig);
1126
+ case "anthropic":
1127
+ return new AnthropicProvider(llmConfig, embeddingConfig);
1128
+ case "ollama":
1129
+ return new OllamaProvider(llmConfig, embeddingConfig);
1130
+ case "rest":
1131
+ case "universal_rest":
1132
+ case "custom":
1133
+ return new UniversalLLMAdapter(llmConfig);
1134
+ default:
1135
+ if (llmConfig.baseUrl || ((_a = llmConfig.options) == null ? void 0 : _a.baseUrl)) {
1136
+ return new UniversalLLMAdapter(llmConfig);
1137
+ }
1138
+ throw new Error(
1139
+ `[LLMFactory] Unknown provider "${llmConfig.provider}". Supported: openai | anthropic | ollama | rest | custom`
1140
+ );
1141
+ }
1142
+ }
1143
+ /**
1144
+ * Creates a dedicated embedding-only provider.
1145
+ * Useful when the LLM provider (e.g. Anthropic) doesn't support embeddings.
1146
+ */
1147
+ static createEmbeddingProvider(embeddingConfig) {
1148
+ const fakeLLMConfig = {
1149
+ provider: embeddingConfig.provider,
1150
+ model: embeddingConfig.model,
1151
+ apiKey: embeddingConfig.apiKey,
1152
+ baseUrl: embeddingConfig.baseUrl,
1153
+ options: embeddingConfig.options
1154
+ };
1155
+ return _LLMFactory.create(fakeLLMConfig, embeddingConfig);
1156
+ }
1157
+ };
1158
+
695
1159
  // src/core/ProviderRegistry.ts
696
1160
  var ProviderRegistry = class {
697
1161
  /**
698
- * Register a custom vector provider.
1162
+ * Register a custom vector provider class by name.
1163
+ * The name must match the provider value used in VectorDBConfig.provider.
1164
+ *
1165
+ * @example
1166
+ * ProviderRegistry.registerVectorProvider('my-db', MyCustomProvider);
699
1167
  */
700
1168
  static registerVectorProvider(name, providerClass) {
701
1169
  this.vectorProviders[name] = providerClass;
702
1170
  }
703
1171
  /**
704
1172
  * Creates a vector database provider based on the configuration.
1173
+ * Built-in providers are dynamically imported to avoid bundling all SDKs.
705
1174
  */
706
1175
  static async createVectorProvider(config) {
707
1176
  const { provider } = config;
@@ -709,33 +1178,48 @@ var ProviderRegistry = class {
709
1178
  return new this.vectorProviders[provider](config);
710
1179
  }
711
1180
  switch (provider) {
712
- case "pinecone":
713
- const { PineconeProvider } = await import("./PineconeProvider-ZRAFNFEC.mjs");
1181
+ case "pinecone": {
1182
+ const { PineconeProvider } = await import("./PineconeProvider-E6L5Z2FO.mjs");
714
1183
  return new PineconeProvider(config);
1184
+ }
715
1185
  case "pgvector":
716
- case "postgresql":
1186
+ case "postgresql": {
717
1187
  const { PostgreSQLProvider } = await import("./PostgreSQLProvider-ZNXA67IM.mjs");
718
1188
  return new PostgreSQLProvider(config);
719
- case "mongodb":
1189
+ }
1190
+ case "mongodb": {
720
1191
  const { MongoDBProvider } = await import("./MongoDBProvider-WWVJG3WT.mjs");
721
1192
  return new MongoDBProvider(config);
722
- case "milvus":
723
- const { MilvusProvider } = await import("./MilvusProvider-OO6QGZDZ.mjs");
1193
+ }
1194
+ case "milvus": {
1195
+ const { MilvusProvider } = await import("./MilvusProvider-CJDBCBVI.mjs");
724
1196
  return new MilvusProvider(config);
725
- case "qdrant":
726
- const { QdrantProvider } = await import("./QdrantProvider-VAED5VA7.mjs");
1197
+ }
1198
+ case "qdrant": {
1199
+ const { QdrantProvider } = await import("./QdrantProvider-JITRNJQN.mjs");
727
1200
  return new QdrantProvider(config);
728
- case "chromadb":
729
- const { ChromaDBProvider } = await import("./ChromaDBProvider-QNI7UCX4.mjs");
1201
+ }
1202
+ case "chromadb": {
1203
+ const { ChromaDBProvider } = await import("./ChromaDBProvider-2JZSBOQX.mjs");
730
1204
  return new ChromaDBProvider(config);
731
- case "redis":
732
- const { RedisProvider } = await import("./RedisProvider-ASONNYBI.mjs");
1205
+ }
1206
+ case "redis": {
1207
+ const { RedisProvider } = await import("./RedisProvider-3VKFQXXD.mjs");
733
1208
  return new RedisProvider(config);
734
- case "weaviate":
735
- const { WeaviateProvider } = await import("./WeaviateProvider-PSDCUGC7.mjs");
1209
+ }
1210
+ case "weaviate": {
1211
+ const { WeaviateProvider } = await import("./WeaviateProvider-MXIPP44J.mjs");
736
1212
  return new WeaviateProvider(config);
1213
+ }
1214
+ case "universal_rest":
1215
+ case "rest": {
1216
+ const { UniversalVectorProvider } = await import("./UniversalVectorProvider-E6L4U4OX.mjs");
1217
+ return new UniversalVectorProvider(config);
1218
+ }
737
1219
  default:
738
- throw new Error(`[ProviderRegistry] Unsupported vector provider: ${provider}`);
1220
+ throw new Error(
1221
+ `[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).`
1222
+ );
739
1223
  }
740
1224
  }
741
1225
  /**
@@ -971,6 +1455,89 @@ ${errorMessages}`
971
1455
  }
972
1456
  };
973
1457
 
1458
+ // src/config/EmbeddingStrategy.ts
1459
+ var EmbeddingStrategy = /* @__PURE__ */ ((EmbeddingStrategy2) => {
1460
+ EmbeddingStrategy2["INTEGRATED"] = "integrated";
1461
+ EmbeddingStrategy2["SEPARATE"] = "separate";
1462
+ EmbeddingStrategy2["EXTERNAL"] = "external";
1463
+ return EmbeddingStrategy2;
1464
+ })(EmbeddingStrategy || {});
1465
+ var EmbeddingStrategyResolver = class {
1466
+ /**
1467
+ * Determine strategy based on LLM and embedding configs
1468
+ */
1469
+ static determineStrategy(llmConfig, embeddingConfig) {
1470
+ if (!embeddingConfig) {
1471
+ return this.supportsEmbedding(llmConfig.provider) ? "integrated" /* INTEGRATED */ : "separate" /* SEPARATE */;
1472
+ }
1473
+ if (embeddingConfig.provider !== llmConfig.provider) {
1474
+ return "separate" /* SEPARATE */;
1475
+ }
1476
+ if (embeddingConfig.model !== llmConfig.model) {
1477
+ return "external" /* EXTERNAL */;
1478
+ }
1479
+ return "integrated" /* INTEGRATED */;
1480
+ }
1481
+ /**
1482
+ * Resolve and initialize providers according to the strategy
1483
+ */
1484
+ static async resolve(llmConfig, embeddingConfig) {
1485
+ const strategy = this.determineStrategy(llmConfig, embeddingConfig);
1486
+ const llmProvider = LLMFactory.create(llmConfig, embeddingConfig);
1487
+ let embeddingProvider;
1488
+ switch (strategy) {
1489
+ case "integrated" /* INTEGRATED */:
1490
+ embeddingProvider = llmProvider;
1491
+ break;
1492
+ case "separate" /* SEPARATE */:
1493
+ if (!embeddingConfig) {
1494
+ throw new Error(
1495
+ "[EmbeddingStrategyResolver] SEPARATE strategy requires embeddingConfig"
1496
+ );
1497
+ }
1498
+ embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
1499
+ break;
1500
+ case "external" /* EXTERNAL */:
1501
+ if (!embeddingConfig) {
1502
+ throw new Error(
1503
+ "[EmbeddingStrategyResolver] EXTERNAL strategy requires embeddingConfig"
1504
+ );
1505
+ }
1506
+ embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
1507
+ break;
1508
+ default:
1509
+ throw new Error(`[EmbeddingStrategyResolver] Unknown strategy: ${strategy}`);
1510
+ }
1511
+ return {
1512
+ strategy,
1513
+ embeddingProvider,
1514
+ llmProvider
1515
+ };
1516
+ }
1517
+ /**
1518
+ * Check if an LLM provider natively supports embeddings
1519
+ */
1520
+ static supportsEmbedding(provider) {
1521
+ const providersWithEmbedding = ["openai", "ollama", "rest", "universal_rest"];
1522
+ return providersWithEmbedding.includes(provider);
1523
+ }
1524
+ /**
1525
+ * Get a human-readable description of the strategy
1526
+ */
1527
+ static getDescription(strategy) {
1528
+ switch (strategy) {
1529
+ case "integrated" /* INTEGRATED */:
1530
+ return "Using LLM provider for both chat and embeddings";
1531
+ case "separate" /* SEPARATE */:
1532
+ return "Using separate embedding provider";
1533
+ case "external" /* EXTERNAL */:
1534
+ return "Using external embedding service";
1535
+ default:
1536
+ return "Unknown strategy";
1537
+ }
1538
+ }
1539
+ };
1540
+
974
1541
  // src/core/Pipeline.ts
975
1542
  var Pipeline = class {
976
1543
  constructor(config) {
@@ -985,18 +1552,17 @@ var Pipeline = class {
985
1552
  async initialize() {
986
1553
  if (this.initialised) return;
987
1554
  this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
988
- this.llmProvider = ProviderRegistry.createLLMProvider(this.config.llm, this.config.embedding);
989
- if (this.config.llm.provider === "anthropic") {
990
- const { LLMFactory: LLMFactory2 } = await import("./LLMFactory-JFOY2V4X.mjs");
991
- this.embeddingProvider = LLMFactory2.createEmbeddingProvider(this.config.embedding);
992
- } else {
993
- this.embeddingProvider = this.llmProvider;
994
- }
1555
+ const { llmProvider, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
1556
+ this.config.llm,
1557
+ this.config.embedding
1558
+ );
1559
+ this.llmProvider = llmProvider;
1560
+ this.embeddingProvider = embeddingProvider;
995
1561
  await this.vectorDB.initialize();
996
1562
  this.initialised = true;
997
1563
  }
998
1564
  /**
999
- * Ingest documents with automatic chunking, embedding, and batch processing.
1565
+ * Ingest documents with automatic chunking, embedding, and batch upsert.
1000
1566
  * Handles retries for transient failures.
1001
1567
  */
1002
1568
  async ingest(documents, namespace) {
@@ -1009,19 +1575,18 @@ var Pipeline = class {
1009
1575
  docId: doc.docId,
1010
1576
  metadata: doc.metadata
1011
1577
  });
1012
- const batchOptions = {
1578
+ const embedBatchOptions = {
1013
1579
  batchSize: 50,
1014
- // Embedding batch size
1015
1580
  maxRetries: 3,
1016
1581
  initialDelayMs: 100
1017
1582
  };
1018
1583
  const vectors = await BatchProcessor.mapWithRetry(
1019
1584
  chunks.map((c) => c.content),
1020
1585
  (text) => this.embeddingProvider.embed(text),
1021
- batchOptions
1586
+ embedBatchOptions
1022
1587
  );
1023
1588
  if (vectors.length !== chunks.length) {
1024
- throw new Error(`Embedding failed: got ${vectors.length} vectors for ${chunks.length} chunks`);
1589
+ throw new Error(`Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks`);
1025
1590
  }
1026
1591
  const upsertDocs = chunks.map((chunk, i) => ({
1027
1592
  id: chunk.id,
@@ -1048,10 +1613,7 @@ var Pipeline = class {
1048
1613
  });
1049
1614
  } catch (error) {
1050
1615
  console.error(`[Pipeline] Failed to ingest document ${doc.docId}:`, error);
1051
- results.push({
1052
- docId: doc.docId,
1053
- chunksIngested: 0
1054
- });
1616
+ results.push({ docId: doc.docId, chunksIngested: 0 });
1055
1617
  }
1056
1618
  }
1057
1619
  return results;
@@ -1081,7 +1643,6 @@ ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
1081
1643
  var ProviderHealthCheck = class {
1082
1644
  /**
1083
1645
  * Validates vector database configuration before initialization.
1084
- * Performs connectivity checks and verifies required resources exist.
1085
1646
  */
1086
1647
  static async checkVectorProvider(config) {
1087
1648
  const timestamp = Date.now();
@@ -1089,7 +1650,6 @@ var ProviderHealthCheck = class {
1089
1650
  projectId: "health-check",
1090
1651
  vectorDb: config,
1091
1652
  llm: { provider: "openai", model: "gpt-4o" },
1092
- // dummy
1093
1653
  embedding: { provider: "openai", model: "text-embedding-3-small" }
1094
1654
  });
1095
1655
  const vectorDbErrors = configErrors.filter((e) => e.field.startsWith("vectorDb"));
@@ -1159,10 +1719,7 @@ var ProviderHealthCheck = class {
1159
1719
  return {
1160
1720
  healthy: true,
1161
1721
  provider: "pinecone",
1162
- capabilities: {
1163
- indexes: indexNames.length,
1164
- targetIndex: config.indexName
1165
- },
1722
+ capabilities: { indexes: indexNames.length, targetIndex: config.indexName },
1166
1723
  timestamp
1167
1724
  };
1168
1725
  } catch (error) {
@@ -1181,9 +1738,7 @@ var ProviderHealthCheck = class {
1181
1738
  const client = new Client({ connectionString: opts.connectionString });
1182
1739
  await client.connect();
1183
1740
  const result = await client.query(`
1184
- SELECT EXISTS(
1185
- SELECT 1 FROM pg_extension WHERE extname = 'vector'
1186
- );
1741
+ SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');
1187
1742
  `);
1188
1743
  const hasVector = result.rows[0].exists;
1189
1744
  await client.end();
@@ -1218,7 +1773,7 @@ var ProviderHealthCheck = class {
1218
1773
  provider: "mongodb",
1219
1774
  capabilities: {
1220
1775
  collections: collectionNames.length,
1221
- targetCollection: hasCollection ? opts.collection : "NOT FOUND"
1776
+ targetCollection: hasCollection ? opts.collection : "NOT FOUND (will be created on first insert)"
1222
1777
  },
1223
1778
  timestamp
1224
1779
  };
@@ -1231,16 +1786,16 @@ var ProviderHealthCheck = class {
1231
1786
  };
1232
1787
  }
1233
1788
  }
1789
+ /**
1790
+ * Milvus health check — uses baseUrl/uri (matching MilvusProvider constructor).
1791
+ */
1234
1792
  static async checkMilvus(config, timestamp) {
1235
1793
  const opts = config.options;
1236
- const host = opts.host || "localhost";
1237
- const port = opts.port || 19530;
1794
+ const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : "http://localhost:19530");
1238
1795
  try {
1239
1796
  const controller = new AbortController();
1240
1797
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
1241
- const response = await fetch(`http://${host}:${port}/healthz`, {
1242
- signal: controller.signal
1243
- });
1798
+ const response = await fetch(`${baseUrl}/v1/health`, { signal: controller.signal });
1244
1799
  clearTimeout(timeoutId);
1245
1800
  if (!response.ok) {
1246
1801
  throw new Error(`Health check returned ${response.status}`);
@@ -1248,7 +1803,7 @@ var ProviderHealthCheck = class {
1248
1803
  return {
1249
1804
  healthy: true,
1250
1805
  provider: "milvus",
1251
- capabilities: { endpoint: `${host}:${port}` },
1806
+ capabilities: { endpoint: baseUrl },
1252
1807
  timestamp
1253
1808
  };
1254
1809
  } catch (error) {
@@ -1260,17 +1815,18 @@ var ProviderHealthCheck = class {
1260
1815
  };
1261
1816
  }
1262
1817
  }
1818
+ /**
1819
+ * Qdrant health check — uses baseUrl (matching QdrantProvider constructor).
1820
+ */
1263
1821
  static async checkQdrant(config, timestamp) {
1264
1822
  const opts = config.options;
1265
- const baseUrl = opts.baseUrl || opts.url || "http://localhost:6333";
1823
+ const baseUrl = (opts.baseUrl || opts.url || "http://localhost:6333").replace(/\/$/, "");
1266
1824
  try {
1267
1825
  const apiKey = opts.apiKey;
1268
1826
  const response = await fetch(`${baseUrl}/`, {
1269
1827
  headers: apiKey ? { "api-key": apiKey } : {}
1270
1828
  });
1271
- if (!response.ok) {
1272
- throw new Error(`Health check returned ${response.status}`);
1273
- }
1829
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
1274
1830
  const health = await response.json();
1275
1831
  return {
1276
1832
  healthy: true,
@@ -1287,19 +1843,19 @@ var ProviderHealthCheck = class {
1287
1843
  };
1288
1844
  }
1289
1845
  }
1846
+ /**
1847
+ * ChromaDB health check — uses baseUrl/host (matching ChromaDBProvider constructor).
1848
+ */
1290
1849
  static async checkChromaDB(config, timestamp) {
1291
1850
  const opts = config.options;
1292
- const host = opts.host || "localhost";
1293
- const port = opts.port || 8e3;
1851
+ const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : "http://localhost:8000");
1294
1852
  try {
1295
- const response = await fetch(`http://${host}:${port}/api/v1/heartbeat`);
1296
- if (!response.ok) {
1297
- throw new Error(`Health check returned ${response.status}`);
1298
- }
1853
+ const response = await fetch(`${baseUrl}/api/v1/heartbeat`);
1854
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
1299
1855
  return {
1300
1856
  healthy: true,
1301
1857
  provider: "chromadb",
1302
- capabilities: { endpoint: `${host}:${port}` },
1858
+ capabilities: { endpoint: baseUrl },
1303
1859
  timestamp
1304
1860
  };
1305
1861
  } catch (error) {
@@ -1311,38 +1867,43 @@ var ProviderHealthCheck = class {
1311
1867
  };
1312
1868
  }
1313
1869
  }
1870
+ /**
1871
+ * Redis health check — Redis is TCP-only (no HTTP endpoint).
1872
+ * We report healthy=true with a note; actual connectivity is validated at first operation.
1873
+ */
1314
1874
  static async checkRedis(config, timestamp) {
1315
1875
  const opts = config.options;
1316
- const url = opts.url || `redis://${opts.host}:${opts.port}`;
1317
- try {
1318
- await fetch(url);
1319
- return {
1320
- healthy: true,
1321
- provider: "redis",
1322
- capabilities: { endpoint: url },
1323
- timestamp
1324
- };
1325
- } catch (error) {
1326
- return {
1327
- healthy: false,
1328
- provider: "redis",
1329
- error: `Connection check failed: ${error instanceof Error ? error.message : String(error)}. Ensure Redis is running at ${url}`,
1330
- timestamp
1331
- };
1876
+ const url = opts.baseUrl || opts.url || (opts.host && opts.port ? `redis://${opts.host}:${opts.port}` : "redis://localhost:6379");
1877
+ if (url.startsWith("http")) {
1878
+ try {
1879
+ await fetch(url);
1880
+ return { healthy: true, provider: "redis", capabilities: { endpoint: url }, timestamp };
1881
+ } catch (e) {
1882
+ }
1332
1883
  }
1884
+ return {
1885
+ healthy: true,
1886
+ provider: "redis",
1887
+ capabilities: {
1888
+ endpoint: url,
1889
+ note: "Redis uses TCP; connectivity is validated on first operation."
1890
+ },
1891
+ timestamp
1892
+ };
1333
1893
  }
1894
+ /**
1895
+ * Weaviate health check — uses baseUrl/url (matching WeaviateProvider constructor).
1896
+ */
1334
1897
  static async checkWeaviate(config, timestamp) {
1335
1898
  const opts = config.options;
1336
- const url = (opts.url || "http://localhost:8080").replace(/\/$/, "");
1899
+ const baseUrl = (opts.baseUrl || opts.url || "http://localhost:8080").replace(/\/$/, "");
1337
1900
  try {
1338
- const response = await fetch(`${url}/.well-known/ready`);
1339
- if (!response.ok) {
1340
- throw new Error(`Health check returned ${response.status}`);
1341
- }
1901
+ const response = await fetch(`${baseUrl}/v1/.well-known/ready`);
1902
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
1342
1903
  return {
1343
1904
  healthy: true,
1344
1905
  provider: "weaviate",
1345
- capabilities: { endpoint: url },
1906
+ capabilities: { endpoint: baseUrl },
1346
1907
  timestamp
1347
1908
  };
1348
1909
  } catch (error) {
@@ -1358,12 +1919,7 @@ var ProviderHealthCheck = class {
1358
1919
  const opts = config.options;
1359
1920
  const baseUrl = (opts.baseUrl || "").replace(/\/$/, "");
1360
1921
  if (!baseUrl) {
1361
- return {
1362
- healthy: false,
1363
- provider: "rest",
1364
- error: "baseUrl is required",
1365
- timestamp
1366
- };
1922
+ return { healthy: false, provider: "rest", error: "baseUrl is required", timestamp };
1367
1923
  }
1368
1924
  try {
1369
1925
  const response = await fetch(`${baseUrl}/health`, {
@@ -1419,18 +1975,14 @@ var ProviderHealthCheck = class {
1419
1975
  }
1420
1976
  static async checkOpenAI(config, timestamp) {
1421
1977
  try {
1422
- const OpenAI = await import("openai");
1423
- const client = new OpenAI.default({ apiKey: config.apiKey });
1978
+ const OpenAI2 = await import("openai");
1979
+ const client = new OpenAI2.default({ apiKey: config.apiKey });
1424
1980
  const models = await client.models.list();
1425
1981
  const hasModel = models.data.some((m) => m.id === config.model);
1426
1982
  return {
1427
1983
  healthy: true,
1428
1984
  provider: "openai",
1429
- capabilities: {
1430
- model: config.model,
1431
- available: hasModel,
1432
- totalModels: models.data.length
1433
- },
1985
+ capabilities: { model: config.model, available: hasModel, totalModels: models.data.length },
1434
1986
  timestamp
1435
1987
  };
1436
1988
  } catch (error) {
@@ -1444,19 +1996,14 @@ var ProviderHealthCheck = class {
1444
1996
  }
1445
1997
  static async checkAnthropic(config, timestamp) {
1446
1998
  try {
1447
- const { default: Anthropic } = await import("@anthropic-ai/sdk");
1448
- const client = new Anthropic({ apiKey: config.apiKey });
1999
+ const { default: Anthropic2 } = await import("@anthropic-ai/sdk");
2000
+ const client = new Anthropic2({ apiKey: config.apiKey });
1449
2001
  await client.messages.create({
1450
2002
  model: config.model,
1451
2003
  max_tokens: 10,
1452
2004
  messages: [{ role: "user", content: "ping" }]
1453
2005
  });
1454
- return {
1455
- healthy: true,
1456
- provider: "anthropic",
1457
- capabilities: { model: config.model },
1458
- timestamp
1459
- };
2006
+ return { healthy: true, provider: "anthropic", capabilities: { model: config.model }, timestamp };
1460
2007
  } catch (error) {
1461
2008
  return {
1462
2009
  healthy: false,
@@ -1470,20 +2017,14 @@ var ProviderHealthCheck = class {
1470
2017
  const baseUrl = (config.baseUrl || "http://localhost:11434").replace(/\/$/, "");
1471
2018
  try {
1472
2019
  const response = await fetch(`${baseUrl}/api/tags`);
1473
- if (!response.ok) {
1474
- throw new Error(`Health check returned ${response.status}`);
1475
- }
2020
+ if (!response.ok) throw new Error(`Health check returned ${response.status}`);
1476
2021
  const data = await response.json();
1477
2022
  const models = data.models || [];
1478
2023
  const hasModel = models.some((m) => m.name === config.model);
1479
2024
  return {
1480
2025
  healthy: true,
1481
2026
  provider: "ollama",
1482
- capabilities: {
1483
- model: config.model,
1484
- available: hasModel,
1485
- totalModels: models.length
1486
- },
2027
+ capabilities: { model: config.model, available: hasModel, totalModels: models.length },
1487
2028
  timestamp
1488
2029
  };
1489
2030
  } catch (error) {
@@ -1500,18 +2041,11 @@ var ProviderHealthCheck = class {
1500
2041
  const baseUrlRaw = config.baseUrl || ((_a = config.options) == null ? void 0 : _a.baseUrl);
1501
2042
  const baseUrl = (typeof baseUrlRaw === "string" ? baseUrlRaw : "").replace(/\/$/, "");
1502
2043
  if (!baseUrl) {
1503
- return {
1504
- healthy: false,
1505
- provider: config.provider,
1506
- error: "baseUrl is required",
1507
- timestamp
1508
- };
2044
+ return { healthy: false, provider: config.provider, error: "baseUrl is required", timestamp };
1509
2045
  }
1510
2046
  try {
1511
2047
  const headers = (_b = config.options) == null ? void 0 : _b.headers;
1512
- const response = await fetch(`${baseUrl}/health`, {
1513
- headers: headers || void 0
1514
- });
2048
+ const response = await fetch(`${baseUrl}/health`, { headers: headers || void 0 });
1515
2049
  return {
1516
2050
  healthy: response.ok,
1517
2051
  provider: config.provider,
@@ -1528,7 +2062,7 @@ var ProviderHealthCheck = class {
1528
2062
  }
1529
2063
  }
1530
2064
  /**
1531
- * Runs comprehensive health checks on all configured providers.
2065
+ * Runs comprehensive health checks on all configured providers in parallel.
1532
2066
  */
1533
2067
  static async checkAll(vectorDbConfig, llmConfig, embeddingConfig) {
1534
2068
  const [vectorDb, llm, embedding] = await Promise.all([
@@ -1753,10 +2287,23 @@ function createUploadHandler(config) {
1753
2287
  export {
1754
2288
  getRagConfig,
1755
2289
  ConfigResolver,
2290
+ ConfigValidator,
1756
2291
  DocumentChunker,
2292
+ OpenAIProvider,
2293
+ AnthropicProvider,
2294
+ OllamaProvider,
2295
+ LLM_PROFILES,
2296
+ VECTOR_PROFILES,
2297
+ UniversalLLMAdapter,
2298
+ LLMFactory,
1757
2299
  ProviderRegistry,
2300
+ BatchProcessor,
2301
+ EmbeddingStrategy,
2302
+ EmbeddingStrategyResolver,
1758
2303
  Pipeline,
2304
+ ProviderHealthCheck,
1759
2305
  VectorPlugin,
2306
+ DocumentParser,
1760
2307
  createChatHandler,
1761
2308
  createIngestHandler,
1762
2309
  createHealthHandler,