@retrivora-ai/rag-engine 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ChromaDBProvider-QNI7UCX4.mjs → ChromaDBProvider-2JZSBOQX.mjs} +1 -1
- package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-CJDBCBVI.mjs} +1 -1
- package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-E6L5Z2FO.mjs} +1 -1
- package/dist/{QdrantProvider-NYGHAA7C.mjs → QdrantProvider-JITRNJQN.mjs} +1 -1
- package/dist/{RagConfig-hBGXJmSx.d.mts → RagConfig-D_rSf8ep.d.mts} +1 -1
- package/dist/{RagConfig-hBGXJmSx.d.ts → RagConfig-D_rSf8ep.d.ts} +1 -1
- package/dist/{RedisProvider-ASONNYBI.mjs → RedisProvider-3VKFQXXD.mjs} +1 -1
- package/dist/UniversalVectorProvider-E6L4U4OX.mjs +9 -0
- package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-MXIPP44J.mjs} +1 -1
- package/dist/{chunk-5K23H7JL.mjs → chunk-26EMHLIN.mjs} +40 -2
- package/dist/{chunk-VPNRDXIA.mjs → chunk-7BQI4A5J.mjs} +17 -11
- package/dist/{chunk-ZM6TYIDH.mjs → chunk-MFWJZVF3.mjs} +3 -1
- package/dist/{chunk-V75V7BT2.mjs → chunk-TSX6DQXX.mjs} +2 -2
- package/dist/{chunk-HUGLYKD6.mjs → chunk-XZPVJS2B.mjs} +27 -9
- package/dist/chunk-Y6HQZDCJ.mjs +156 -0
- package/dist/{chunk-HSBXE2WV.mjs → chunk-YIYDJQJM.mjs} +745 -192
- package/dist/{chunk-7NXI6ZWX.mjs → chunk-YST6KYBJ.mjs} +8 -5
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +924 -626
- package/dist/handlers/index.mjs +1 -2
- package/dist/index-BJ8CUArE.d.mts +114 -0
- package/dist/index-DtNprGGj.d.ts +114 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/server.d.mts +575 -17
- package/dist/server.d.ts +575 -17
- package/dist/server.js +1280 -643
- package/dist/server.mjs +314 -16
- package/package.json +11 -2
- package/src/config/ConfigBuilder.ts +373 -0
- package/src/config/EmbeddingStrategy.ts +147 -0
- package/src/config/serverConfig.ts +51 -17
- package/src/core/ConfigValidator.ts +77 -52
- package/src/core/Pipeline.ts +28 -26
- package/src/core/PluginManager.ts +277 -0
- package/src/core/ProviderHealthCheck.ts +79 -140
- package/src/core/ProviderRegistry.ts +38 -15
- package/src/providers/vectordb/ChromaDBProvider.ts +37 -12
- package/src/providers/vectordb/MilvusProvider.ts +25 -10
- package/src/providers/vectordb/PineconeProvider.ts +17 -2
- package/src/providers/vectordb/QdrantProvider.ts +46 -2
- package/src/providers/vectordb/RedisProvider.ts +34 -11
- package/src/providers/vectordb/UniversalVectorProvider.ts +220 -0
- package/src/providers/vectordb/WeaviateProvider.ts +17 -10
- package/src/server.ts +28 -10
- package/dist/LLMFactory-JFOY2V4X.mjs +0 -8
- package/dist/chunk-JI6VD5TJ.mjs +0 -387
- package/dist/index-Bx182KKn.d.ts +0 -64
- package/dist/index-Ck2pt7-8.d.mts +0 -64
- package/src/test-refactor.ts +0 -59
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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 = [
|
|
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,48 +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
|
-
|
|
52
|
-
|
|
53
|
-
vectorDbOptions.
|
|
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 = (
|
|
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 = (
|
|
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
93
|
}
|
|
71
94
|
const llmApiKeyByProvider = {
|
|
72
95
|
openai: readString(env, "OPENAI_API_KEY"),
|
|
73
96
|
anthropic: readString(env, "ANTHROPIC_API_KEY"),
|
|
74
97
|
ollama: void 0,
|
|
75
|
-
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")
|
|
76
101
|
};
|
|
77
102
|
const embeddingApiKeyByProvider = {
|
|
78
103
|
openai: readString(env, "OPENAI_API_KEY"),
|
|
79
104
|
ollama: void 0,
|
|
80
|
-
|
|
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")
|
|
81
107
|
};
|
|
82
108
|
return {
|
|
83
109
|
projectId,
|
|
84
110
|
vectorDb: {
|
|
85
111
|
provider: vectorProvider,
|
|
86
|
-
indexName: (
|
|
112
|
+
indexName: (_s = readString(env, "VECTOR_DB_INDEX")) != null ? _s : "rag-index",
|
|
87
113
|
options: vectorDbOptions
|
|
88
114
|
},
|
|
89
115
|
llm: {
|
|
90
116
|
provider: llmProvider,
|
|
91
|
-
model: (
|
|
92
|
-
apiKey: (
|
|
117
|
+
model: (_t = readString(env, "LLM_MODEL")) != null ? _t : "gpt-4o",
|
|
118
|
+
apiKey: (_u = llmApiKeyByProvider[llmProvider]) != null ? _u : "",
|
|
93
119
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
94
120
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
95
121
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 1024),
|
|
@@ -100,7 +126,7 @@ function getRagConfig(env = process.env) {
|
|
|
100
126
|
},
|
|
101
127
|
embedding: {
|
|
102
128
|
provider: embeddingProvider,
|
|
103
|
-
model: (
|
|
129
|
+
model: (_v = readString(env, "EMBEDDING_MODEL")) != null ? _v : "text-embedding-3-small",
|
|
104
130
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
105
131
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
106
132
|
dimensions: embeddingDimensions,
|
|
@@ -109,16 +135,16 @@ function getRagConfig(env = process.env) {
|
|
|
109
135
|
}
|
|
110
136
|
},
|
|
111
137
|
ui: {
|
|
112
|
-
title: (
|
|
113
|
-
subtitle: (
|
|
114
|
-
primaryColor: (
|
|
115
|
-
accentColor: (
|
|
116
|
-
logoUrl: (
|
|
117
|
-
placeholder: (
|
|
118
|
-
showSources: ((
|
|
119
|
-
welcomeMessage: (
|
|
120
|
-
visualStyle: (
|
|
121
|
-
borderRadius: (
|
|
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"
|
|
122
148
|
},
|
|
123
149
|
rag: {
|
|
124
150
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
@@ -194,7 +220,7 @@ var ConfigValidator = class {
|
|
|
194
220
|
errors.push({
|
|
195
221
|
field: "embedding",
|
|
196
222
|
message: "Embedding config is required when using Anthropic LLM",
|
|
197
|
-
suggestion: 'Provide embedding config with provider (e.g., "openai")',
|
|
223
|
+
suggestion: 'Provide embedding config with provider (e.g., "openai" or "ollama")',
|
|
198
224
|
severity: "error"
|
|
199
225
|
});
|
|
200
226
|
}
|
|
@@ -256,6 +282,10 @@ var ConfigValidator = class {
|
|
|
256
282
|
}
|
|
257
283
|
return errors;
|
|
258
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Pinecone — only needs apiKey (environment was removed in SDK v7+).
|
|
287
|
+
* Options key: { apiKey: string }
|
|
288
|
+
*/
|
|
259
289
|
static validatePineconeConfig(config) {
|
|
260
290
|
const errors = [];
|
|
261
291
|
const opts = config.options;
|
|
@@ -267,16 +297,12 @@ var ConfigValidator = class {
|
|
|
267
297
|
severity: "error"
|
|
268
298
|
});
|
|
269
299
|
}
|
|
270
|
-
if (!opts.environment) {
|
|
271
|
-
errors.push({
|
|
272
|
-
field: "vectorDb.options.environment",
|
|
273
|
-
message: "Pinecone environment is required",
|
|
274
|
-
suggestion: 'Set PINECONE_ENVIRONMENT environment variable (e.g., "gcp-starter")',
|
|
275
|
-
severity: "error"
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
300
|
return errors;
|
|
279
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* PostgreSQL / pgvector — needs a connection string.
|
|
304
|
+
* Options key: { connectionString: string }
|
|
305
|
+
*/
|
|
280
306
|
static validatePostgresConfig(config) {
|
|
281
307
|
const errors = [];
|
|
282
308
|
const opts = config.options;
|
|
@@ -290,6 +316,10 @@ var ConfigValidator = class {
|
|
|
290
316
|
}
|
|
291
317
|
return errors;
|
|
292
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* MongoDB — needs uri, database, and collection.
|
|
321
|
+
* Options keys: { uri: string, database: string, collection: string }
|
|
322
|
+
*/
|
|
293
323
|
static validateMongoDBConfig(config) {
|
|
294
324
|
const errors = [];
|
|
295
325
|
const opts = config.options;
|
|
@@ -319,27 +349,30 @@ var ConfigValidator = class {
|
|
|
319
349
|
}
|
|
320
350
|
return errors;
|
|
321
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
|
+
*/
|
|
322
357
|
static validateMilvusConfig(config) {
|
|
323
358
|
const errors = [];
|
|
324
359
|
const opts = config.options;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
message: "Milvus host is required",
|
|
329
|
-
suggestion: "Set MILVUS_HOST environment variable",
|
|
330
|
-
severity: "error"
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
if (!opts.port) {
|
|
360
|
+
const hasBaseUrl = Boolean(opts.baseUrl || opts.uri);
|
|
361
|
+
const hasHostPort = Boolean(opts.host && opts.port);
|
|
362
|
+
if (!hasBaseUrl && !hasHostPort) {
|
|
334
363
|
errors.push({
|
|
335
|
-
field: "vectorDb.options.
|
|
336
|
-
message:
|
|
337
|
-
suggestion: "Set
|
|
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",
|
|
338
367
|
severity: "error"
|
|
339
368
|
});
|
|
340
369
|
}
|
|
341
370
|
return errors;
|
|
342
371
|
}
|
|
372
|
+
/**
|
|
373
|
+
* Qdrant — needs baseUrl (or url alias).
|
|
374
|
+
* Options keys: { baseUrl: string, apiKey?: string }
|
|
375
|
+
*/
|
|
343
376
|
static validateQdrantConfig(config) {
|
|
344
377
|
const errors = [];
|
|
345
378
|
const opts = config.options;
|
|
@@ -353,38 +386,55 @@ var ConfigValidator = class {
|
|
|
353
386
|
}
|
|
354
387
|
return errors;
|
|
355
388
|
}
|
|
389
|
+
/**
|
|
390
|
+
* ChromaDB — accepts baseUrl OR host.
|
|
391
|
+
* ChromaDBProvider reads opts.baseUrl.
|
|
392
|
+
* Options keys: { baseUrl?: string, host?: string, port?: number }
|
|
393
|
+
*/
|
|
356
394
|
static validateChromaDBConfig(config) {
|
|
357
395
|
const errors = [];
|
|
358
396
|
const opts = config.options;
|
|
359
|
-
if (!opts.
|
|
397
|
+
if (!opts.baseUrl && !opts.host) {
|
|
360
398
|
errors.push({
|
|
361
|
-
field: "vectorDb.options.
|
|
362
|
-
message:
|
|
363
|
-
suggestion: "Set
|
|
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",
|
|
364
402
|
severity: "error"
|
|
365
403
|
});
|
|
366
404
|
}
|
|
367
405
|
return errors;
|
|
368
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
|
+
*/
|
|
369
412
|
static validateRedisConfig(config) {
|
|
370
413
|
const errors = [];
|
|
371
414
|
const opts = config.options;
|
|
372
|
-
|
|
415
|
+
const hasUrl = Boolean(opts.baseUrl || opts.url);
|
|
416
|
+
const hasHostPort = Boolean(opts.host && opts.port);
|
|
417
|
+
if (!hasUrl && !hasHostPort) {
|
|
373
418
|
errors.push({
|
|
374
|
-
field: "vectorDb.options.
|
|
375
|
-
message: "Redis connection
|
|
376
|
-
suggestion: "Set REDIS_URL
|
|
419
|
+
field: "vectorDb.options.baseUrl",
|
|
420
|
+
message: "Redis connection is required: provide baseUrl/url or host + port",
|
|
421
|
+
suggestion: "Set REDIS_URL environment variable",
|
|
377
422
|
severity: "error"
|
|
378
423
|
});
|
|
379
424
|
}
|
|
380
425
|
return errors;
|
|
381
426
|
}
|
|
427
|
+
/**
|
|
428
|
+
* Weaviate — accepts baseUrl OR url.
|
|
429
|
+
* WeaviateProvider reads opts.baseUrl.
|
|
430
|
+
* Options keys: { baseUrl?: string, url?: string, apiKey?: string }
|
|
431
|
+
*/
|
|
382
432
|
static validateWeaviateConfig(config) {
|
|
383
433
|
const errors = [];
|
|
384
434
|
const opts = config.options;
|
|
385
|
-
if (!opts.url) {
|
|
435
|
+
if (!opts.baseUrl && !opts.url) {
|
|
386
436
|
errors.push({
|
|
387
|
-
field: "vectorDb.options.
|
|
437
|
+
field: "vectorDb.options.baseUrl",
|
|
388
438
|
message: "Weaviate instance URL is required",
|
|
389
439
|
suggestion: "Set WEAVIATE_URL environment variable",
|
|
390
440
|
severity: "error"
|
|
@@ -392,6 +442,10 @@ var ConfigValidator = class {
|
|
|
392
442
|
}
|
|
393
443
|
return errors;
|
|
394
444
|
}
|
|
445
|
+
/**
|
|
446
|
+
* Universal REST / custom REST adapter.
|
|
447
|
+
* Options key: { baseUrl: string }
|
|
448
|
+
*/
|
|
395
449
|
static validateRestConfig(config) {
|
|
396
450
|
const errors = [];
|
|
397
451
|
const opts = config.options;
|
|
@@ -499,7 +553,7 @@ var ConfigValidator = class {
|
|
|
499
553
|
errors.push({
|
|
500
554
|
field: "embedding.model",
|
|
501
555
|
message: "Embedding model name is required",
|
|
502
|
-
suggestion: 'e.g., "text-embedding-3-small" for OpenAI',
|
|
556
|
+
suggestion: 'e.g., "text-embedding-3-small" for OpenAI, "nomic-embed-text" for Ollama',
|
|
503
557
|
severity: "error"
|
|
504
558
|
});
|
|
505
559
|
}
|
|
@@ -514,7 +568,7 @@ var ConfigValidator = class {
|
|
|
514
568
|
if (config.provider === "ollama" && !config.baseUrl) {
|
|
515
569
|
errors.push({
|
|
516
570
|
field: "embedding.baseUrl",
|
|
517
|
-
message: "Ollama base URL is required",
|
|
571
|
+
message: "Ollama base URL is required for embedding",
|
|
518
572
|
suggestion: "Set EMBEDDING_BASE_URL environment variable",
|
|
519
573
|
severity: "error"
|
|
520
574
|
});
|
|
@@ -603,9 +657,11 @@ var ConfigValidator = class {
|
|
|
603
657
|
return errors;
|
|
604
658
|
}
|
|
605
659
|
static isValidCSSColor(color) {
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
660
|
+
const hexRegex = /^#([0-9a-f]{3}){1,2}$/i;
|
|
661
|
+
const rgbRegex = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/i;
|
|
662
|
+
const hslRegex = /^hsla?\((\d+),\s*(\d+)%,\s*(\d+)%(?:,\s*(\d+(?:\.\d+)?))?\)$/i;
|
|
663
|
+
const namedColors = ["red", "blue", "green", "black", "white", "transparent"];
|
|
664
|
+
return hexRegex.test(color) || rgbRegex.test(color) || hslRegex.test(color) || namedColors.includes(color.toLowerCase());
|
|
609
665
|
}
|
|
610
666
|
/**
|
|
611
667
|
* Throws if there are error-level validation issues.
|
|
@@ -689,16 +745,432 @@ var DocumentChunker = class {
|
|
|
689
745
|
}
|
|
690
746
|
};
|
|
691
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
|
+
|
|
692
1159
|
// src/core/ProviderRegistry.ts
|
|
693
1160
|
var ProviderRegistry = class {
|
|
694
1161
|
/**
|
|
695
|
-
* 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);
|
|
696
1167
|
*/
|
|
697
1168
|
static registerVectorProvider(name, providerClass) {
|
|
698
1169
|
this.vectorProviders[name] = providerClass;
|
|
699
1170
|
}
|
|
700
1171
|
/**
|
|
701
1172
|
* Creates a vector database provider based on the configuration.
|
|
1173
|
+
* Built-in providers are dynamically imported to avoid bundling all SDKs.
|
|
702
1174
|
*/
|
|
703
1175
|
static async createVectorProvider(config) {
|
|
704
1176
|
const { provider } = config;
|
|
@@ -706,33 +1178,48 @@ var ProviderRegistry = class {
|
|
|
706
1178
|
return new this.vectorProviders[provider](config);
|
|
707
1179
|
}
|
|
708
1180
|
switch (provider) {
|
|
709
|
-
case "pinecone":
|
|
710
|
-
const { PineconeProvider } = await import("./PineconeProvider-
|
|
1181
|
+
case "pinecone": {
|
|
1182
|
+
const { PineconeProvider } = await import("./PineconeProvider-E6L5Z2FO.mjs");
|
|
711
1183
|
return new PineconeProvider(config);
|
|
1184
|
+
}
|
|
712
1185
|
case "pgvector":
|
|
713
|
-
case "postgresql":
|
|
1186
|
+
case "postgresql": {
|
|
714
1187
|
const { PostgreSQLProvider } = await import("./PostgreSQLProvider-ZNXA67IM.mjs");
|
|
715
1188
|
return new PostgreSQLProvider(config);
|
|
716
|
-
|
|
1189
|
+
}
|
|
1190
|
+
case "mongodb": {
|
|
717
1191
|
const { MongoDBProvider } = await import("./MongoDBProvider-WWVJG3WT.mjs");
|
|
718
1192
|
return new MongoDBProvider(config);
|
|
719
|
-
|
|
720
|
-
|
|
1193
|
+
}
|
|
1194
|
+
case "milvus": {
|
|
1195
|
+
const { MilvusProvider } = await import("./MilvusProvider-CJDBCBVI.mjs");
|
|
721
1196
|
return new MilvusProvider(config);
|
|
722
|
-
|
|
723
|
-
|
|
1197
|
+
}
|
|
1198
|
+
case "qdrant": {
|
|
1199
|
+
const { QdrantProvider } = await import("./QdrantProvider-JITRNJQN.mjs");
|
|
724
1200
|
return new QdrantProvider(config);
|
|
725
|
-
|
|
726
|
-
|
|
1201
|
+
}
|
|
1202
|
+
case "chromadb": {
|
|
1203
|
+
const { ChromaDBProvider } = await import("./ChromaDBProvider-2JZSBOQX.mjs");
|
|
727
1204
|
return new ChromaDBProvider(config);
|
|
728
|
-
|
|
729
|
-
|
|
1205
|
+
}
|
|
1206
|
+
case "redis": {
|
|
1207
|
+
const { RedisProvider } = await import("./RedisProvider-3VKFQXXD.mjs");
|
|
730
1208
|
return new RedisProvider(config);
|
|
731
|
-
|
|
732
|
-
|
|
1209
|
+
}
|
|
1210
|
+
case "weaviate": {
|
|
1211
|
+
const { WeaviateProvider } = await import("./WeaviateProvider-MXIPP44J.mjs");
|
|
733
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
|
+
}
|
|
734
1219
|
default:
|
|
735
|
-
throw new Error(
|
|
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
|
+
);
|
|
736
1223
|
}
|
|
737
1224
|
}
|
|
738
1225
|
/**
|
|
@@ -968,6 +1455,89 @@ ${errorMessages}`
|
|
|
968
1455
|
}
|
|
969
1456
|
};
|
|
970
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
|
+
|
|
971
1541
|
// src/core/Pipeline.ts
|
|
972
1542
|
var Pipeline = class {
|
|
973
1543
|
constructor(config) {
|
|
@@ -982,18 +1552,17 @@ var Pipeline = class {
|
|
|
982
1552
|
async initialize() {
|
|
983
1553
|
if (this.initialised) return;
|
|
984
1554
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
}
|
|
1555
|
+
const { llmProvider, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
|
|
1556
|
+
this.config.llm,
|
|
1557
|
+
this.config.embedding
|
|
1558
|
+
);
|
|
1559
|
+
this.llmProvider = llmProvider;
|
|
1560
|
+
this.embeddingProvider = embeddingProvider;
|
|
992
1561
|
await this.vectorDB.initialize();
|
|
993
1562
|
this.initialised = true;
|
|
994
1563
|
}
|
|
995
1564
|
/**
|
|
996
|
-
* Ingest documents with automatic chunking, embedding, and batch
|
|
1565
|
+
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
997
1566
|
* Handles retries for transient failures.
|
|
998
1567
|
*/
|
|
999
1568
|
async ingest(documents, namespace) {
|
|
@@ -1006,19 +1575,18 @@ var Pipeline = class {
|
|
|
1006
1575
|
docId: doc.docId,
|
|
1007
1576
|
metadata: doc.metadata
|
|
1008
1577
|
});
|
|
1009
|
-
const
|
|
1578
|
+
const embedBatchOptions = {
|
|
1010
1579
|
batchSize: 50,
|
|
1011
|
-
// Embedding batch size
|
|
1012
1580
|
maxRetries: 3,
|
|
1013
1581
|
initialDelayMs: 100
|
|
1014
1582
|
};
|
|
1015
1583
|
const vectors = await BatchProcessor.mapWithRetry(
|
|
1016
1584
|
chunks.map((c) => c.content),
|
|
1017
1585
|
(text) => this.embeddingProvider.embed(text),
|
|
1018
|
-
|
|
1586
|
+
embedBatchOptions
|
|
1019
1587
|
);
|
|
1020
1588
|
if (vectors.length !== chunks.length) {
|
|
1021
|
-
throw new Error(`Embedding
|
|
1589
|
+
throw new Error(`Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks`);
|
|
1022
1590
|
}
|
|
1023
1591
|
const upsertDocs = chunks.map((chunk, i) => ({
|
|
1024
1592
|
id: chunk.id,
|
|
@@ -1045,10 +1613,7 @@ var Pipeline = class {
|
|
|
1045
1613
|
});
|
|
1046
1614
|
} catch (error) {
|
|
1047
1615
|
console.error(`[Pipeline] Failed to ingest document ${doc.docId}:`, error);
|
|
1048
|
-
results.push({
|
|
1049
|
-
docId: doc.docId,
|
|
1050
|
-
chunksIngested: 0
|
|
1051
|
-
});
|
|
1616
|
+
results.push({ docId: doc.docId, chunksIngested: 0 });
|
|
1052
1617
|
}
|
|
1053
1618
|
}
|
|
1054
1619
|
return results;
|
|
@@ -1078,7 +1643,6 @@ ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
|
1078
1643
|
var ProviderHealthCheck = class {
|
|
1079
1644
|
/**
|
|
1080
1645
|
* Validates vector database configuration before initialization.
|
|
1081
|
-
* Performs connectivity checks and verifies required resources exist.
|
|
1082
1646
|
*/
|
|
1083
1647
|
static async checkVectorProvider(config) {
|
|
1084
1648
|
const timestamp = Date.now();
|
|
@@ -1086,7 +1650,6 @@ var ProviderHealthCheck = class {
|
|
|
1086
1650
|
projectId: "health-check",
|
|
1087
1651
|
vectorDb: config,
|
|
1088
1652
|
llm: { provider: "openai", model: "gpt-4o" },
|
|
1089
|
-
// dummy
|
|
1090
1653
|
embedding: { provider: "openai", model: "text-embedding-3-small" }
|
|
1091
1654
|
});
|
|
1092
1655
|
const vectorDbErrors = configErrors.filter((e) => e.field.startsWith("vectorDb"));
|
|
@@ -1156,10 +1719,7 @@ var ProviderHealthCheck = class {
|
|
|
1156
1719
|
return {
|
|
1157
1720
|
healthy: true,
|
|
1158
1721
|
provider: "pinecone",
|
|
1159
|
-
capabilities: {
|
|
1160
|
-
indexes: indexNames.length,
|
|
1161
|
-
targetIndex: config.indexName
|
|
1162
|
-
},
|
|
1722
|
+
capabilities: { indexes: indexNames.length, targetIndex: config.indexName },
|
|
1163
1723
|
timestamp
|
|
1164
1724
|
};
|
|
1165
1725
|
} catch (error) {
|
|
@@ -1178,9 +1738,7 @@ var ProviderHealthCheck = class {
|
|
|
1178
1738
|
const client = new Client({ connectionString: opts.connectionString });
|
|
1179
1739
|
await client.connect();
|
|
1180
1740
|
const result = await client.query(`
|
|
1181
|
-
SELECT EXISTS(
|
|
1182
|
-
SELECT 1 FROM pg_extension WHERE extname = 'vector'
|
|
1183
|
-
);
|
|
1741
|
+
SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');
|
|
1184
1742
|
`);
|
|
1185
1743
|
const hasVector = result.rows[0].exists;
|
|
1186
1744
|
await client.end();
|
|
@@ -1215,7 +1773,7 @@ var ProviderHealthCheck = class {
|
|
|
1215
1773
|
provider: "mongodb",
|
|
1216
1774
|
capabilities: {
|
|
1217
1775
|
collections: collectionNames.length,
|
|
1218
|
-
targetCollection: hasCollection ? opts.collection : "NOT FOUND"
|
|
1776
|
+
targetCollection: hasCollection ? opts.collection : "NOT FOUND (will be created on first insert)"
|
|
1219
1777
|
},
|
|
1220
1778
|
timestamp
|
|
1221
1779
|
};
|
|
@@ -1228,16 +1786,16 @@ var ProviderHealthCheck = class {
|
|
|
1228
1786
|
};
|
|
1229
1787
|
}
|
|
1230
1788
|
}
|
|
1789
|
+
/**
|
|
1790
|
+
* Milvus health check — uses baseUrl/uri (matching MilvusProvider constructor).
|
|
1791
|
+
*/
|
|
1231
1792
|
static async checkMilvus(config, timestamp) {
|
|
1232
1793
|
const opts = config.options;
|
|
1233
|
-
const
|
|
1234
|
-
const port = opts.port || 19530;
|
|
1794
|
+
const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : "http://localhost:19530");
|
|
1235
1795
|
try {
|
|
1236
1796
|
const controller = new AbortController();
|
|
1237
1797
|
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
1238
|
-
const response = await fetch(
|
|
1239
|
-
signal: controller.signal
|
|
1240
|
-
});
|
|
1798
|
+
const response = await fetch(`${baseUrl}/v1/health`, { signal: controller.signal });
|
|
1241
1799
|
clearTimeout(timeoutId);
|
|
1242
1800
|
if (!response.ok) {
|
|
1243
1801
|
throw new Error(`Health check returned ${response.status}`);
|
|
@@ -1245,7 +1803,7 @@ var ProviderHealthCheck = class {
|
|
|
1245
1803
|
return {
|
|
1246
1804
|
healthy: true,
|
|
1247
1805
|
provider: "milvus",
|
|
1248
|
-
capabilities: { endpoint:
|
|
1806
|
+
capabilities: { endpoint: baseUrl },
|
|
1249
1807
|
timestamp
|
|
1250
1808
|
};
|
|
1251
1809
|
} catch (error) {
|
|
@@ -1257,14 +1815,18 @@ var ProviderHealthCheck = class {
|
|
|
1257
1815
|
};
|
|
1258
1816
|
}
|
|
1259
1817
|
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Qdrant health check — uses baseUrl (matching QdrantProvider constructor).
|
|
1820
|
+
*/
|
|
1260
1821
|
static async checkQdrant(config, timestamp) {
|
|
1261
1822
|
const opts = config.options;
|
|
1262
|
-
const baseUrl = opts.baseUrl || opts.url || "http://localhost:6333";
|
|
1823
|
+
const baseUrl = (opts.baseUrl || opts.url || "http://localhost:6333").replace(/\/$/, "");
|
|
1263
1824
|
try {
|
|
1264
|
-
const
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
}
|
|
1825
|
+
const apiKey = opts.apiKey;
|
|
1826
|
+
const response = await fetch(`${baseUrl}/`, {
|
|
1827
|
+
headers: apiKey ? { "api-key": apiKey } : {}
|
|
1828
|
+
});
|
|
1829
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
1268
1830
|
const health = await response.json();
|
|
1269
1831
|
return {
|
|
1270
1832
|
healthy: true,
|
|
@@ -1281,19 +1843,19 @@ var ProviderHealthCheck = class {
|
|
|
1281
1843
|
};
|
|
1282
1844
|
}
|
|
1283
1845
|
}
|
|
1846
|
+
/**
|
|
1847
|
+
* ChromaDB health check — uses baseUrl/host (matching ChromaDBProvider constructor).
|
|
1848
|
+
*/
|
|
1284
1849
|
static async checkChromaDB(config, timestamp) {
|
|
1285
1850
|
const opts = config.options;
|
|
1286
|
-
const
|
|
1287
|
-
const port = opts.port || 8e3;
|
|
1851
|
+
const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : "http://localhost:8000");
|
|
1288
1852
|
try {
|
|
1289
|
-
const response = await fetch(
|
|
1290
|
-
if (!response.ok) {
|
|
1291
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
1292
|
-
}
|
|
1853
|
+
const response = await fetch(`${baseUrl}/api/v1/heartbeat`);
|
|
1854
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
1293
1855
|
return {
|
|
1294
1856
|
healthy: true,
|
|
1295
1857
|
provider: "chromadb",
|
|
1296
|
-
capabilities: { endpoint:
|
|
1858
|
+
capabilities: { endpoint: baseUrl },
|
|
1297
1859
|
timestamp
|
|
1298
1860
|
};
|
|
1299
1861
|
} catch (error) {
|
|
@@ -1305,38 +1867,43 @@ var ProviderHealthCheck = class {
|
|
|
1305
1867
|
};
|
|
1306
1868
|
}
|
|
1307
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
|
+
*/
|
|
1308
1874
|
static async checkRedis(config, timestamp) {
|
|
1309
1875
|
const opts = config.options;
|
|
1310
|
-
const url = opts.url || `redis://${opts.host}:${opts.port}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
healthy: true,
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
timestamp
|
|
1318
|
-
};
|
|
1319
|
-
} catch (error) {
|
|
1320
|
-
return {
|
|
1321
|
-
healthy: false,
|
|
1322
|
-
provider: "redis",
|
|
1323
|
-
error: `Connection check failed: ${error instanceof Error ? error.message : String(error)}. Ensure Redis is running at ${url}`,
|
|
1324
|
-
timestamp
|
|
1325
|
-
};
|
|
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
|
+
}
|
|
1326
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
|
+
};
|
|
1327
1893
|
}
|
|
1894
|
+
/**
|
|
1895
|
+
* Weaviate health check — uses baseUrl/url (matching WeaviateProvider constructor).
|
|
1896
|
+
*/
|
|
1328
1897
|
static async checkWeaviate(config, timestamp) {
|
|
1329
1898
|
const opts = config.options;
|
|
1330
|
-
const
|
|
1899
|
+
const baseUrl = (opts.baseUrl || opts.url || "http://localhost:8080").replace(/\/$/, "");
|
|
1331
1900
|
try {
|
|
1332
|
-
const response = await fetch(`${
|
|
1333
|
-
if (!response.ok) {
|
|
1334
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
1335
|
-
}
|
|
1901
|
+
const response = await fetch(`${baseUrl}/v1/.well-known/ready`);
|
|
1902
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
1336
1903
|
return {
|
|
1337
1904
|
healthy: true,
|
|
1338
1905
|
provider: "weaviate",
|
|
1339
|
-
capabilities: { endpoint:
|
|
1906
|
+
capabilities: { endpoint: baseUrl },
|
|
1340
1907
|
timestamp
|
|
1341
1908
|
};
|
|
1342
1909
|
} catch (error) {
|
|
@@ -1352,12 +1919,7 @@ var ProviderHealthCheck = class {
|
|
|
1352
1919
|
const opts = config.options;
|
|
1353
1920
|
const baseUrl = (opts.baseUrl || "").replace(/\/$/, "");
|
|
1354
1921
|
if (!baseUrl) {
|
|
1355
|
-
return {
|
|
1356
|
-
healthy: false,
|
|
1357
|
-
provider: "rest",
|
|
1358
|
-
error: "baseUrl is required",
|
|
1359
|
-
timestamp
|
|
1360
|
-
};
|
|
1922
|
+
return { healthy: false, provider: "rest", error: "baseUrl is required", timestamp };
|
|
1361
1923
|
}
|
|
1362
1924
|
try {
|
|
1363
1925
|
const response = await fetch(`${baseUrl}/health`, {
|
|
@@ -1413,18 +1975,14 @@ var ProviderHealthCheck = class {
|
|
|
1413
1975
|
}
|
|
1414
1976
|
static async checkOpenAI(config, timestamp) {
|
|
1415
1977
|
try {
|
|
1416
|
-
const
|
|
1417
|
-
const client = new
|
|
1978
|
+
const OpenAI2 = await import("openai");
|
|
1979
|
+
const client = new OpenAI2.default({ apiKey: config.apiKey });
|
|
1418
1980
|
const models = await client.models.list();
|
|
1419
1981
|
const hasModel = models.data.some((m) => m.id === config.model);
|
|
1420
1982
|
return {
|
|
1421
1983
|
healthy: true,
|
|
1422
1984
|
provider: "openai",
|
|
1423
|
-
capabilities: {
|
|
1424
|
-
model: config.model,
|
|
1425
|
-
available: hasModel,
|
|
1426
|
-
totalModels: models.data.length
|
|
1427
|
-
},
|
|
1985
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.data.length },
|
|
1428
1986
|
timestamp
|
|
1429
1987
|
};
|
|
1430
1988
|
} catch (error) {
|
|
@@ -1438,19 +1996,14 @@ var ProviderHealthCheck = class {
|
|
|
1438
1996
|
}
|
|
1439
1997
|
static async checkAnthropic(config, timestamp) {
|
|
1440
1998
|
try {
|
|
1441
|
-
const { default:
|
|
1442
|
-
const client = new
|
|
1999
|
+
const { default: Anthropic2 } = await import("@anthropic-ai/sdk");
|
|
2000
|
+
const client = new Anthropic2({ apiKey: config.apiKey });
|
|
1443
2001
|
await client.messages.create({
|
|
1444
2002
|
model: config.model,
|
|
1445
2003
|
max_tokens: 10,
|
|
1446
2004
|
messages: [{ role: "user", content: "ping" }]
|
|
1447
2005
|
});
|
|
1448
|
-
return {
|
|
1449
|
-
healthy: true,
|
|
1450
|
-
provider: "anthropic",
|
|
1451
|
-
capabilities: { model: config.model },
|
|
1452
|
-
timestamp
|
|
1453
|
-
};
|
|
2006
|
+
return { healthy: true, provider: "anthropic", capabilities: { model: config.model }, timestamp };
|
|
1454
2007
|
} catch (error) {
|
|
1455
2008
|
return {
|
|
1456
2009
|
healthy: false,
|
|
@@ -1464,20 +2017,14 @@ var ProviderHealthCheck = class {
|
|
|
1464
2017
|
const baseUrl = (config.baseUrl || "http://localhost:11434").replace(/\/$/, "");
|
|
1465
2018
|
try {
|
|
1466
2019
|
const response = await fetch(`${baseUrl}/api/tags`);
|
|
1467
|
-
if (!response.ok) {
|
|
1468
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
1469
|
-
}
|
|
2020
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
1470
2021
|
const data = await response.json();
|
|
1471
2022
|
const models = data.models || [];
|
|
1472
2023
|
const hasModel = models.some((m) => m.name === config.model);
|
|
1473
2024
|
return {
|
|
1474
2025
|
healthy: true,
|
|
1475
2026
|
provider: "ollama",
|
|
1476
|
-
capabilities: {
|
|
1477
|
-
model: config.model,
|
|
1478
|
-
available: hasModel,
|
|
1479
|
-
totalModels: models.length
|
|
1480
|
-
},
|
|
2027
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.length },
|
|
1481
2028
|
timestamp
|
|
1482
2029
|
};
|
|
1483
2030
|
} catch (error) {
|
|
@@ -1494,18 +2041,11 @@ var ProviderHealthCheck = class {
|
|
|
1494
2041
|
const baseUrlRaw = config.baseUrl || ((_a = config.options) == null ? void 0 : _a.baseUrl);
|
|
1495
2042
|
const baseUrl = (typeof baseUrlRaw === "string" ? baseUrlRaw : "").replace(/\/$/, "");
|
|
1496
2043
|
if (!baseUrl) {
|
|
1497
|
-
return {
|
|
1498
|
-
healthy: false,
|
|
1499
|
-
provider: config.provider,
|
|
1500
|
-
error: "baseUrl is required",
|
|
1501
|
-
timestamp
|
|
1502
|
-
};
|
|
2044
|
+
return { healthy: false, provider: config.provider, error: "baseUrl is required", timestamp };
|
|
1503
2045
|
}
|
|
1504
2046
|
try {
|
|
1505
2047
|
const headers = (_b = config.options) == null ? void 0 : _b.headers;
|
|
1506
|
-
const response = await fetch(`${baseUrl}/health`, {
|
|
1507
|
-
headers: headers || void 0
|
|
1508
|
-
});
|
|
2048
|
+
const response = await fetch(`${baseUrl}/health`, { headers: headers || void 0 });
|
|
1509
2049
|
return {
|
|
1510
2050
|
healthy: response.ok,
|
|
1511
2051
|
provider: config.provider,
|
|
@@ -1522,7 +2062,7 @@ var ProviderHealthCheck = class {
|
|
|
1522
2062
|
}
|
|
1523
2063
|
}
|
|
1524
2064
|
/**
|
|
1525
|
-
* Runs comprehensive health checks on all configured providers.
|
|
2065
|
+
* Runs comprehensive health checks on all configured providers in parallel.
|
|
1526
2066
|
*/
|
|
1527
2067
|
static async checkAll(vectorDbConfig, llmConfig, embeddingConfig) {
|
|
1528
2068
|
const [vectorDb, llm, embedding] = await Promise.all([
|
|
@@ -1747,10 +2287,23 @@ function createUploadHandler(config) {
|
|
|
1747
2287
|
export {
|
|
1748
2288
|
getRagConfig,
|
|
1749
2289
|
ConfigResolver,
|
|
2290
|
+
ConfigValidator,
|
|
1750
2291
|
DocumentChunker,
|
|
2292
|
+
OpenAIProvider,
|
|
2293
|
+
AnthropicProvider,
|
|
2294
|
+
OllamaProvider,
|
|
2295
|
+
LLM_PROFILES,
|
|
2296
|
+
VECTOR_PROFILES,
|
|
2297
|
+
UniversalLLMAdapter,
|
|
2298
|
+
LLMFactory,
|
|
1751
2299
|
ProviderRegistry,
|
|
2300
|
+
BatchProcessor,
|
|
2301
|
+
EmbeddingStrategy,
|
|
2302
|
+
EmbeddingStrategyResolver,
|
|
1752
2303
|
Pipeline,
|
|
2304
|
+
ProviderHealthCheck,
|
|
1753
2305
|
VectorPlugin,
|
|
2306
|
+
DocumentParser,
|
|
1754
2307
|
createChatHandler,
|
|
1755
2308
|
createIngestHandler,
|
|
1756
2309
|
createHealthHandler,
|