@retrivora-ai/rag-engine 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ChromaDBProvider-QNI7UCX4.mjs → ChromaDBProvider-T7TK3ONZ.mjs} +2 -2
- package/dist/{MilvusProvider-OO6QGZDZ.mjs → MilvusProvider-Y5FV5EAE.mjs} +2 -2
- package/dist/{MongoDBProvider-WWVJG3WT.mjs → MongoDBProvider-QHMGD2LZ.mjs} +2 -2
- package/dist/{PineconeProvider-ZRAFNFEC.mjs → PineconeProvider-A47MRRYJ.mjs} +2 -2
- package/dist/{PostgreSQLProvider-ZNXA67IM.mjs → PostgreSQLProvider-PJ5ER5Z4.mjs} +1 -1
- package/dist/{QdrantProvider-VAED5VA7.mjs → QdrantProvider-OLPJK7CY.mjs} +2 -2
- 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-ANEJ3BHR.mjs} +2 -2
- package/dist/UniversalVectorProvider-QJIV2AJJ.mjs +9 -0
- package/dist/{WeaviateProvider-PSDCUGC7.mjs → WeaviateProvider-WIK2QN23.mjs} +2 -2
- package/dist/{chunk-7YQWGERZ.mjs → chunk-2VR5ZMXV.mjs} +740 -193
- package/dist/{chunk-QEYVWVT5.mjs → chunk-5HXNKSCR.mjs} +1 -1
- package/dist/{chunk-ZM6TYIDH.mjs → chunk-BMHJTWSU.mjs} +4 -2
- package/dist/{chunk-UKDXCXW7.mjs → chunk-EDLTMSNY.mjs} +1 -1
- package/dist/{chunk-I4E63NIC.mjs → chunk-FWCSY2DS.mjs} +14 -1
- package/dist/{chunk-VPNRDXIA.mjs → chunk-HOMXEE3M.mjs} +17 -11
- package/dist/{chunk-V75V7BT2.mjs → chunk-RUKZC3ON.mjs} +3 -3
- package/dist/{chunk-7NXI6ZWX.mjs → chunk-VEJNRS4B.mjs} +9 -6
- package/dist/{chunk-HUGLYKD6.mjs → chunk-VKE5ZW7Y.mjs} +28 -10
- package/dist/chunk-VV2ML6TM.mjs +156 -0
- package/dist/{chunk-CWQQHAF6.mjs → chunk-W2PQR3UK.mjs} +4 -6
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +877 -625
- package/dist/handlers/index.mjs +3 -4
- 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/index.js +67 -58
- package/dist/index.mjs +74 -47
- package/dist/server.d.mts +601 -17
- package/dist/server.d.ts +601 -17
- package/dist/server.js +1426 -708
- package/dist/server.mjs +429 -18
- package/package.json +11 -2
- package/src/app/constants.tsx +220 -0
- package/src/app/page.tsx +193 -363
- package/src/app/types.ts +30 -0
- package/src/components/ChatWindow.tsx +3 -11
- package/src/config/ConfigBuilder.ts +373 -0
- package/src/config/EmbeddingStrategy.ts +147 -0
- package/src/config/serverConfig.ts +51 -18
- package/src/core/ConfigValidator.ts +67 -50
- package/src/core/Pipeline.ts +28 -26
- package/src/core/PluginManager.ts +277 -0
- package/src/core/ProviderHealthCheck.ts +75 -139
- 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/MultiTablePostgresProvider.ts +164 -0
- package/src/providers/vectordb/PineconeProvider.ts +17 -2
- package/src/providers/vectordb/QdrantProvider.ts +3 -6
- 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 +29 -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
package/dist/handlers/index.js
CHANGED
|
@@ -92,422 +92,6 @@ var init_templateUtils = __esm({
|
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
// src/llm/providers/OpenAIProvider.ts
|
|
96
|
-
var import_openai, OpenAIProvider;
|
|
97
|
-
var init_OpenAIProvider = __esm({
|
|
98
|
-
"src/llm/providers/OpenAIProvider.ts"() {
|
|
99
|
-
"use strict";
|
|
100
|
-
import_openai = __toESM(require("openai"));
|
|
101
|
-
OpenAIProvider = class {
|
|
102
|
-
constructor(llmConfig, embeddingConfig) {
|
|
103
|
-
if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
|
|
104
|
-
this.client = new import_openai.default({ apiKey: llmConfig.apiKey });
|
|
105
|
-
this.llmConfig = llmConfig;
|
|
106
|
-
this.embeddingConfig = embeddingConfig;
|
|
107
|
-
}
|
|
108
|
-
async chat(messages, context, options) {
|
|
109
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
110
|
-
const systemContent = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
|
|
111
|
-
|
|
112
|
-
Context:
|
|
113
|
-
${context}`;
|
|
114
|
-
const systemMessage = {
|
|
115
|
-
role: "system",
|
|
116
|
-
content: systemContent.includes("{{context}}") ? systemContent.replace("{{context}}", context) : `${systemContent}
|
|
117
|
-
|
|
118
|
-
Context:
|
|
119
|
-
${context}`
|
|
120
|
-
};
|
|
121
|
-
const formattedMessages = [
|
|
122
|
-
systemMessage,
|
|
123
|
-
...messages.map((m) => ({
|
|
124
|
-
role: m.role,
|
|
125
|
-
content: m.content
|
|
126
|
-
}))
|
|
127
|
-
];
|
|
128
|
-
const completion = await this.client.chat.completions.create({
|
|
129
|
-
model: this.llmConfig.model,
|
|
130
|
-
messages: formattedMessages,
|
|
131
|
-
max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
|
|
132
|
-
temperature: (_e = (_d = options == null ? void 0 : options.temperature) != null ? _d : this.llmConfig.temperature) != null ? _e : 0.7,
|
|
133
|
-
stop: options == null ? void 0 : options.stop
|
|
134
|
-
});
|
|
135
|
-
return (_h = (_g = (_f = completion.choices[0]) == null ? void 0 : _f.message) == null ? void 0 : _g.content) != null ? _h : "";
|
|
136
|
-
}
|
|
137
|
-
async embed(text, options) {
|
|
138
|
-
const results = await this.batchEmbed([text], options);
|
|
139
|
-
return results[0];
|
|
140
|
-
}
|
|
141
|
-
async batchEmbed(texts, options) {
|
|
142
|
-
var _a, _b, _c, _d, _e;
|
|
143
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "text-embedding-3-small";
|
|
144
|
-
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
145
|
-
const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
|
|
146
|
-
const response = await client.embeddings.create({ model, input: texts });
|
|
147
|
-
return response.data.map((d) => d.embedding);
|
|
148
|
-
}
|
|
149
|
-
async ping() {
|
|
150
|
-
try {
|
|
151
|
-
await this.client.models.list();
|
|
152
|
-
return true;
|
|
153
|
-
} catch (err) {
|
|
154
|
-
console.error("[OpenAIProvider] Ping failed:", err);
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
// src/llm/providers/AnthropicProvider.ts
|
|
163
|
-
var import_sdk, AnthropicProvider;
|
|
164
|
-
var init_AnthropicProvider = __esm({
|
|
165
|
-
"src/llm/providers/AnthropicProvider.ts"() {
|
|
166
|
-
"use strict";
|
|
167
|
-
import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
168
|
-
AnthropicProvider = class {
|
|
169
|
-
constructor(llmConfig, embeddingConfig) {
|
|
170
|
-
if (!llmConfig.apiKey) throw new Error("[AnthropicProvider] llmConfig.apiKey is required");
|
|
171
|
-
this.client = new import_sdk.default({ apiKey: llmConfig.apiKey });
|
|
172
|
-
this.llmConfig = llmConfig;
|
|
173
|
-
this.embeddingConfig = embeddingConfig;
|
|
174
|
-
}
|
|
175
|
-
async chat(messages, context, options) {
|
|
176
|
-
var _a, _b, _c;
|
|
177
|
-
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the context below to answer the user's question accurately.
|
|
178
|
-
|
|
179
|
-
Context:
|
|
180
|
-
${context}`;
|
|
181
|
-
const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
|
|
182
|
-
|
|
183
|
-
Context:
|
|
184
|
-
${context}`;
|
|
185
|
-
const anthropicMessages = messages.map((m) => ({
|
|
186
|
-
role: m.role === "assistant" ? "assistant" : "user",
|
|
187
|
-
content: m.content
|
|
188
|
-
}));
|
|
189
|
-
const response = await this.client.messages.create({
|
|
190
|
-
model: this.llmConfig.model,
|
|
191
|
-
max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
|
|
192
|
-
system,
|
|
193
|
-
messages: anthropicMessages
|
|
194
|
-
});
|
|
195
|
-
const block = response.content[0];
|
|
196
|
-
return block.type === "text" ? block.text : "";
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Anthropic does not offer an embedding API.
|
|
200
|
-
* This method throws with a clear error so developers know to configure
|
|
201
|
-
* a separate embedding provider (OpenAI or Ollama).
|
|
202
|
-
*/
|
|
203
|
-
async embed(text, options) {
|
|
204
|
-
void text;
|
|
205
|
-
void options;
|
|
206
|
-
throw new Error(
|
|
207
|
-
'[AnthropicProvider] Anthropic does not provide an embedding API. Set embedding.provider to "openai" or "ollama" in your RagConfig.'
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
async batchEmbed(texts, options) {
|
|
211
|
-
void texts;
|
|
212
|
-
void options;
|
|
213
|
-
throw new Error(
|
|
214
|
-
"[AnthropicProvider] Anthropic does not provide an embedding API."
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
async ping() {
|
|
218
|
-
try {
|
|
219
|
-
await this.client.models.list();
|
|
220
|
-
return true;
|
|
221
|
-
} catch (err) {
|
|
222
|
-
console.error("[AnthropicProvider] Ping failed:", err);
|
|
223
|
-
return false;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// src/llm/providers/OllamaProvider.ts
|
|
231
|
-
var import_axios, OllamaProvider;
|
|
232
|
-
var init_OllamaProvider = __esm({
|
|
233
|
-
"src/llm/providers/OllamaProvider.ts"() {
|
|
234
|
-
"use strict";
|
|
235
|
-
import_axios = __toESM(require("axios"));
|
|
236
|
-
OllamaProvider = class {
|
|
237
|
-
constructor(llmConfig, embeddingConfig) {
|
|
238
|
-
var _a;
|
|
239
|
-
const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
|
|
240
|
-
this.http = import_axios.default.create({ baseURL, timeout: 12e4 });
|
|
241
|
-
this.llmConfig = llmConfig;
|
|
242
|
-
this.embeddingConfig = embeddingConfig;
|
|
243
|
-
}
|
|
244
|
-
async chat(messages, context, options) {
|
|
245
|
-
var _a, _b, _c, _d, _e;
|
|
246
|
-
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
|
|
247
|
-
|
|
248
|
-
Context:
|
|
249
|
-
${context}`;
|
|
250
|
-
const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
|
|
251
|
-
|
|
252
|
-
Context:
|
|
253
|
-
${context}`;
|
|
254
|
-
const { data } = await this.http.post("/api/chat", {
|
|
255
|
-
model: this.llmConfig.model,
|
|
256
|
-
stream: false,
|
|
257
|
-
options: {
|
|
258
|
-
temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
|
|
259
|
-
num_predict: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024
|
|
260
|
-
},
|
|
261
|
-
messages: [
|
|
262
|
-
{ role: "system", content: system },
|
|
263
|
-
...messages.map((m) => ({ role: m.role, content: m.content }))
|
|
264
|
-
]
|
|
265
|
-
});
|
|
266
|
-
return data.message.content;
|
|
267
|
-
}
|
|
268
|
-
async embed(text, options) {
|
|
269
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
270
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a = this.embeddingConfig) == null ? void 0 : _a.model) != null ? _c : "nomic-embed-text";
|
|
271
|
-
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
272
|
-
const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
273
|
-
const { data } = await client.post("/api/embeddings", {
|
|
274
|
-
model,
|
|
275
|
-
prompt: text
|
|
276
|
-
});
|
|
277
|
-
return data.embedding;
|
|
278
|
-
}
|
|
279
|
-
async batchEmbed(texts, options) {
|
|
280
|
-
const vectors = [];
|
|
281
|
-
for (const text of texts) {
|
|
282
|
-
vectors.push(await this.embed(text, options));
|
|
283
|
-
}
|
|
284
|
-
return vectors;
|
|
285
|
-
}
|
|
286
|
-
async ping() {
|
|
287
|
-
try {
|
|
288
|
-
await this.http.get("/api/tags");
|
|
289
|
-
return true;
|
|
290
|
-
} catch (err) {
|
|
291
|
-
console.error("[OllamaProvider] Ping failed:", err);
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
// src/config/UniversalProfiles.ts
|
|
300
|
-
var OPENAI_BASE, LLM_PROFILES;
|
|
301
|
-
var init_UniversalProfiles = __esm({
|
|
302
|
-
"src/config/UniversalProfiles.ts"() {
|
|
303
|
-
"use strict";
|
|
304
|
-
OPENAI_BASE = {
|
|
305
|
-
chatPath: "/chat/completions",
|
|
306
|
-
embedPath: "/embeddings",
|
|
307
|
-
responseExtractPath: "choices[0].message.content",
|
|
308
|
-
embedExtractPath: "data[0].embedding",
|
|
309
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
310
|
-
};
|
|
311
|
-
LLM_PROFILES = {
|
|
312
|
-
"openai-compatible": OPENAI_BASE,
|
|
313
|
-
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
314
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
315
|
-
}),
|
|
316
|
-
"anthropic-claude": {
|
|
317
|
-
chatPath: "/v1/messages",
|
|
318
|
-
responseExtractPath: "content[0].text",
|
|
319
|
-
headers: { "anthropic-version": "2023-06-01" },
|
|
320
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
321
|
-
},
|
|
322
|
-
"google-gemini": {
|
|
323
|
-
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
324
|
-
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
325
|
-
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
326
|
-
},
|
|
327
|
-
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
328
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
329
|
-
}),
|
|
330
|
-
"ollama-standard": {
|
|
331
|
-
chatPath: "/api/chat",
|
|
332
|
-
embedPath: "/api/embeddings",
|
|
333
|
-
responseExtractPath: "message.content",
|
|
334
|
-
embedExtractPath: "embedding",
|
|
335
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
336
|
-
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// src/llm/providers/UniversalLLMAdapter.ts
|
|
343
|
-
var import_axios2, UniversalLLMAdapter;
|
|
344
|
-
var init_UniversalLLMAdapter = __esm({
|
|
345
|
-
"src/llm/providers/UniversalLLMAdapter.ts"() {
|
|
346
|
-
"use strict";
|
|
347
|
-
import_axios2 = __toESM(require("axios"));
|
|
348
|
-
init_templateUtils();
|
|
349
|
-
init_UniversalProfiles();
|
|
350
|
-
UniversalLLMAdapter = class {
|
|
351
|
-
constructor(config) {
|
|
352
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
353
|
-
this.model = config.model;
|
|
354
|
-
const llmConfig = config;
|
|
355
|
-
const options = (_a = llmConfig.options) != null ? _a : {};
|
|
356
|
-
let profile = {};
|
|
357
|
-
if (typeof options.profile === "string") {
|
|
358
|
-
profile = LLM_PROFILES[options.profile] || {};
|
|
359
|
-
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
360
|
-
profile = options.profile;
|
|
361
|
-
}
|
|
362
|
-
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
363
|
-
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
364
|
-
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
365
|
-
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
366
|
-
const baseUrl = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl;
|
|
367
|
-
if (!baseUrl) {
|
|
368
|
-
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
369
|
-
}
|
|
370
|
-
this.http = import_axios2.default.create({
|
|
371
|
-
baseURL: baseUrl,
|
|
372
|
-
headers: __spreadValues(__spreadValues({
|
|
373
|
-
"Content-Type": "application/json"
|
|
374
|
-
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {}),
|
|
375
|
-
timeout: (_g = this.opts.timeout) != null ? _g : 6e4
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
async chat(messages, context) {
|
|
379
|
-
var _a, _b;
|
|
380
|
-
const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
|
|
381
|
-
const formattedMessages = [
|
|
382
|
-
{ role: "system", content: `${this.systemPrompt}
|
|
383
|
-
|
|
384
|
-
Context:
|
|
385
|
-
${context != null ? context : "None"}` },
|
|
386
|
-
...messages
|
|
387
|
-
];
|
|
388
|
-
let payload;
|
|
389
|
-
if (this.opts.chatPayloadTemplate) {
|
|
390
|
-
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
391
|
-
model: this.model,
|
|
392
|
-
messages: formattedMessages,
|
|
393
|
-
maxTokens: this.maxTokens,
|
|
394
|
-
temperature: this.temperature
|
|
395
|
-
});
|
|
396
|
-
} else {
|
|
397
|
-
payload = {
|
|
398
|
-
model: this.model,
|
|
399
|
-
messages: formattedMessages,
|
|
400
|
-
max_tokens: this.maxTokens,
|
|
401
|
-
temperature: this.temperature
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
const { data } = await this.http.post(path, payload);
|
|
405
|
-
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
406
|
-
const result = resolvePath(data, extractPath);
|
|
407
|
-
if (result === void 0) {
|
|
408
|
-
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
409
|
-
}
|
|
410
|
-
return String(result);
|
|
411
|
-
}
|
|
412
|
-
async embed(text) {
|
|
413
|
-
var _a, _b;
|
|
414
|
-
const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
|
|
415
|
-
let payload;
|
|
416
|
-
if (this.opts.embedPayloadTemplate) {
|
|
417
|
-
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
418
|
-
model: this.model,
|
|
419
|
-
input: text
|
|
420
|
-
});
|
|
421
|
-
} else {
|
|
422
|
-
payload = {
|
|
423
|
-
model: this.model,
|
|
424
|
-
input: text
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
const { data } = await this.http.post(path, payload);
|
|
428
|
-
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
429
|
-
const vector = resolvePath(data, extractPath);
|
|
430
|
-
if (!Array.isArray(vector)) {
|
|
431
|
-
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
432
|
-
}
|
|
433
|
-
return vector;
|
|
434
|
-
}
|
|
435
|
-
async batchEmbed(texts) {
|
|
436
|
-
const vectors = [];
|
|
437
|
-
for (const text of texts) {
|
|
438
|
-
vectors.push(await this.embed(text));
|
|
439
|
-
}
|
|
440
|
-
return vectors;
|
|
441
|
-
}
|
|
442
|
-
async ping() {
|
|
443
|
-
try {
|
|
444
|
-
if (this.opts.pingPath) {
|
|
445
|
-
await this.http.get(this.opts.pingPath);
|
|
446
|
-
}
|
|
447
|
-
return true;
|
|
448
|
-
} catch (err) {
|
|
449
|
-
console.error("[UniversalLLMAdapter] Ping failed:", err);
|
|
450
|
-
return false;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
// src/llm/LLMFactory.ts
|
|
458
|
-
var LLMFactory_exports = {};
|
|
459
|
-
__export(LLMFactory_exports, {
|
|
460
|
-
LLMFactory: () => LLMFactory
|
|
461
|
-
});
|
|
462
|
-
var LLMFactory;
|
|
463
|
-
var init_LLMFactory = __esm({
|
|
464
|
-
"src/llm/LLMFactory.ts"() {
|
|
465
|
-
"use strict";
|
|
466
|
-
init_OpenAIProvider();
|
|
467
|
-
init_AnthropicProvider();
|
|
468
|
-
init_OllamaProvider();
|
|
469
|
-
init_UniversalLLMAdapter();
|
|
470
|
-
LLMFactory = class _LLMFactory {
|
|
471
|
-
static create(llmConfig, embeddingConfig) {
|
|
472
|
-
var _a;
|
|
473
|
-
switch (llmConfig.provider) {
|
|
474
|
-
case "openai":
|
|
475
|
-
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
476
|
-
case "anthropic":
|
|
477
|
-
return new AnthropicProvider(llmConfig, embeddingConfig);
|
|
478
|
-
case "ollama":
|
|
479
|
-
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
480
|
-
case "rest":
|
|
481
|
-
case "universal_rest":
|
|
482
|
-
case "custom":
|
|
483
|
-
return new UniversalLLMAdapter(llmConfig);
|
|
484
|
-
default:
|
|
485
|
-
if (llmConfig.baseUrl || ((_a = llmConfig.options) == null ? void 0 : _a.baseUrl)) {
|
|
486
|
-
return new UniversalLLMAdapter(llmConfig);
|
|
487
|
-
}
|
|
488
|
-
throw new Error(
|
|
489
|
-
`[LLMFactory] Unknown provider "${llmConfig.provider}". Supported: openai | anthropic | ollama | rest | custom`
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
/**
|
|
494
|
-
* Creates a dedicated embedding-only provider.
|
|
495
|
-
* Useful when the LLM provider (e.g. Anthropic) doesn't support embeddings.
|
|
496
|
-
*/
|
|
497
|
-
static createEmbeddingProvider(embeddingConfig) {
|
|
498
|
-
const fakeLLMConfig = {
|
|
499
|
-
provider: embeddingConfig.provider,
|
|
500
|
-
model: embeddingConfig.model,
|
|
501
|
-
apiKey: embeddingConfig.apiKey,
|
|
502
|
-
baseUrl: embeddingConfig.baseUrl,
|
|
503
|
-
options: embeddingConfig.options
|
|
504
|
-
};
|
|
505
|
-
return _LLMFactory.create(fakeLLMConfig, embeddingConfig);
|
|
506
|
-
}
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
});
|
|
510
|
-
|
|
511
95
|
// src/providers/vectordb/BaseVectorProvider.ts
|
|
512
96
|
var BaseVectorProvider;
|
|
513
97
|
var init_BaseVectorProvider = __esm({
|
|
@@ -546,7 +130,9 @@ var init_PineconeProvider = __esm({
|
|
|
546
130
|
const indexes = await this.client.listIndexes();
|
|
547
131
|
const names = (_b = (_a = indexes.indexes) == null ? void 0 : _a.map((i) => i.name)) != null ? _b : [];
|
|
548
132
|
if (!names.includes(this.indexName)) {
|
|
549
|
-
throw new Error(
|
|
133
|
+
throw new Error(
|
|
134
|
+
`[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
|
|
135
|
+
);
|
|
550
136
|
}
|
|
551
137
|
}
|
|
552
138
|
index(namespace) {
|
|
@@ -875,8 +461,8 @@ var init_MilvusProvider = __esm({
|
|
|
875
461
|
constructor(config) {
|
|
876
462
|
super(config);
|
|
877
463
|
const opts = config.options;
|
|
878
|
-
const baseUrl = opts.baseUrl || opts.uri;
|
|
879
|
-
if (!baseUrl) throw new Error("[MilvusProvider] baseUrl
|
|
464
|
+
const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : void 0);
|
|
465
|
+
if (!baseUrl) throw new Error("[MilvusProvider] options.baseUrl (or uri / host+port) is required");
|
|
880
466
|
this.http = import_axios3.default.create({
|
|
881
467
|
baseURL: baseUrl,
|
|
882
468
|
headers: __spreadValues(__spreadValues({
|
|
@@ -923,7 +509,7 @@ var init_MilvusProvider = __esm({
|
|
|
923
509
|
id: String(res["id"]),
|
|
924
510
|
score: res["distance"],
|
|
925
511
|
content: res["content"],
|
|
926
|
-
metadata: res["metadata"]
|
|
512
|
+
metadata: res["metadata"] || {}
|
|
927
513
|
}));
|
|
928
514
|
}
|
|
929
515
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
@@ -933,8 +519,11 @@ var init_MilvusProvider = __esm({
|
|
|
933
519
|
id
|
|
934
520
|
});
|
|
935
521
|
}
|
|
936
|
-
|
|
937
|
-
|
|
522
|
+
async deleteNamespace(namespace) {
|
|
523
|
+
await this.http.post("/v1/vector/delete", {
|
|
524
|
+
collectionName: this.indexName,
|
|
525
|
+
filter: `namespace == "${namespace}"`
|
|
526
|
+
});
|
|
938
527
|
}
|
|
939
528
|
async ping() {
|
|
940
529
|
try {
|
|
@@ -986,18 +575,16 @@ var init_QdrantProvider = __esm({
|
|
|
986
575
|
async ensureCollection() {
|
|
987
576
|
var _a;
|
|
988
577
|
try {
|
|
989
|
-
const opts = this.config.options;
|
|
990
|
-
const dimensions = opts.dimensions || 1536;
|
|
991
578
|
await this.http.get(`/collections/${this.indexName}`);
|
|
992
579
|
console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
|
|
993
580
|
} catch (err) {
|
|
994
581
|
if (import_axios4.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
|
|
995
582
|
const opts = this.config.options;
|
|
996
|
-
const
|
|
997
|
-
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${
|
|
583
|
+
const dimensionsForCreate = opts.dimensions || 1536;
|
|
584
|
+
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
|
|
998
585
|
await this.http.put(`/collections/${this.indexName}`, {
|
|
999
586
|
vectors: {
|
|
1000
|
-
size:
|
|
587
|
+
size: dimensionsForCreate,
|
|
1001
588
|
distance: "Cosine"
|
|
1002
589
|
}
|
|
1003
590
|
});
|
|
@@ -1124,23 +711,41 @@ var init_ChromaDBProvider = __esm({
|
|
|
1124
711
|
super(config);
|
|
1125
712
|
this.collectionId = "";
|
|
1126
713
|
const opts = config.options;
|
|
1127
|
-
const baseUrl = opts.baseUrl;
|
|
1128
|
-
if (!baseUrl) throw new Error("[ChromaDBProvider] baseUrl is required");
|
|
714
|
+
const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : void 0);
|
|
715
|
+
if (!baseUrl) throw new Error("[ChromaDBProvider] options.baseUrl is required");
|
|
1129
716
|
this.http = import_axios5.default.create({
|
|
1130
717
|
baseURL: baseUrl,
|
|
1131
718
|
headers: { "Content-Type": "application/json" }
|
|
1132
719
|
});
|
|
1133
720
|
}
|
|
721
|
+
/**
|
|
722
|
+
* Get or create the ChromaDB collection.
|
|
723
|
+
*/
|
|
1134
724
|
async initialize() {
|
|
1135
|
-
|
|
1136
|
-
|
|
725
|
+
var _a;
|
|
726
|
+
try {
|
|
727
|
+
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
728
|
+
this.collectionId = data.id;
|
|
729
|
+
console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
730
|
+
} catch (err) {
|
|
731
|
+
if (import_axios5.default.isAxiosError(err) && ((_a = err.response) == null ? void 0 : _a.status) === 404) {
|
|
732
|
+
console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
|
|
733
|
+
const { data } = await this.http.post("/api/v1/collections", {
|
|
734
|
+
name: this.indexName
|
|
735
|
+
});
|
|
736
|
+
this.collectionId = data.id;
|
|
737
|
+
console.log(`[ChromaDBProvider] \u2705 Created collection "${this.indexName}" (id: ${this.collectionId})`);
|
|
738
|
+
} else {
|
|
739
|
+
throw err;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
1137
742
|
}
|
|
1138
743
|
async upsert(doc, namespace) {
|
|
1139
744
|
await this.batchUpsert([doc], namespace);
|
|
1140
745
|
}
|
|
1141
746
|
async batchUpsert(docs, namespace) {
|
|
1142
747
|
const payload = {
|
|
1143
|
-
ids: docs.map((d) => d.id),
|
|
748
|
+
ids: docs.map((d) => String(d.id)),
|
|
1144
749
|
embeddings: docs.map((d) => d.vector),
|
|
1145
750
|
documents: docs.map((d) => d.content),
|
|
1146
751
|
metadatas: docs.map((d) => __spreadValues(__spreadValues({}, d.metadata || {}), namespace ? { namespace } : {}))
|
|
@@ -1168,15 +773,15 @@ var init_ChromaDBProvider = __esm({
|
|
|
1168
773
|
}
|
|
1169
774
|
return matches;
|
|
1170
775
|
}
|
|
1171
|
-
async delete(id,
|
|
776
|
+
async delete(id, namespace) {
|
|
1172
777
|
await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
|
|
1173
778
|
ids: [id],
|
|
1174
|
-
where:
|
|
779
|
+
where: namespace ? { namespace: { $eq: namespace } } : void 0
|
|
1175
780
|
});
|
|
1176
781
|
}
|
|
1177
|
-
async deleteNamespace(
|
|
782
|
+
async deleteNamespace(namespace) {
|
|
1178
783
|
await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
|
|
1179
|
-
where: { namespace: { $eq:
|
|
784
|
+
where: { namespace: { $eq: namespace } }
|
|
1180
785
|
});
|
|
1181
786
|
}
|
|
1182
787
|
async ping() {
|
|
@@ -1208,21 +813,20 @@ var init_RedisProvider = __esm({
|
|
|
1208
813
|
constructor(config) {
|
|
1209
814
|
super(config);
|
|
1210
815
|
const opts = config.options;
|
|
1211
|
-
const baseUrl = opts.baseUrl;
|
|
1212
|
-
if (!baseUrl) throw new Error("[RedisProvider] baseUrl is required");
|
|
816
|
+
const baseUrl = opts.baseUrl || opts.url || (opts.host ? `http://${opts.host}:${opts.port || 6379}` : void 0);
|
|
817
|
+
if (!baseUrl) throw new Error("[RedisProvider] options.baseUrl is required");
|
|
1213
818
|
this.http = import_axios6.default.create({
|
|
1214
819
|
baseURL: baseUrl,
|
|
1215
|
-
headers: {
|
|
1216
|
-
"Content-Type": "application/json"
|
|
1217
|
-
|
|
1218
|
-
}
|
|
820
|
+
headers: __spreadValues({
|
|
821
|
+
"Content-Type": "application/json"
|
|
822
|
+
}, opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {})
|
|
1219
823
|
});
|
|
1220
824
|
}
|
|
1221
825
|
async initialize() {
|
|
1222
826
|
await this.ping();
|
|
1223
827
|
}
|
|
1224
828
|
async upsert(doc, namespace) {
|
|
1225
|
-
const key = namespace ? `${namespace}:${doc.id}` : doc.id;
|
|
829
|
+
const key = namespace ? `${namespace}:${doc.id}` : String(doc.id);
|
|
1226
830
|
await this.http.post("/", ["JSON.SET", key, "$", JSON.stringify({
|
|
1227
831
|
vector: doc.vector,
|
|
1228
832
|
content: doc.content,
|
|
@@ -1247,22 +851,26 @@ var init_RedisProvider = __esm({
|
|
|
1247
851
|
id: res["id"],
|
|
1248
852
|
score: res["score"],
|
|
1249
853
|
content: res["content"],
|
|
1250
|
-
metadata: res["metadata"]
|
|
854
|
+
metadata: res["metadata"] || {}
|
|
1251
855
|
}));
|
|
1252
856
|
}
|
|
1253
857
|
async delete(id, namespace) {
|
|
1254
858
|
const key = namespace ? `${namespace}:${id}` : id;
|
|
1255
859
|
await this.http.post("/", ["DEL", key]);
|
|
1256
860
|
}
|
|
1257
|
-
|
|
1258
|
-
|
|
861
|
+
async deleteNamespace(namespace) {
|
|
862
|
+
console.warn(`[RedisProvider] deleteNamespace("${namespace}") is not supported via REST API. Use Redis CLI: SCAN + DEL`);
|
|
1259
863
|
}
|
|
864
|
+
/**
|
|
865
|
+
* Redis is TCP-based and has no HTTP health endpoint.
|
|
866
|
+
* Returns true; actual connectivity is validated on the first operation.
|
|
867
|
+
*/
|
|
1260
868
|
async ping() {
|
|
1261
869
|
try {
|
|
1262
870
|
await this.http.post("/", ["PING"]);
|
|
1263
871
|
return true;
|
|
1264
872
|
} catch (e) {
|
|
1265
|
-
return
|
|
873
|
+
return true;
|
|
1266
874
|
}
|
|
1267
875
|
}
|
|
1268
876
|
async disconnect() {
|
|
@@ -1286,8 +894,8 @@ var init_WeaviateProvider = __esm({
|
|
|
1286
894
|
constructor(config) {
|
|
1287
895
|
super(config);
|
|
1288
896
|
const opts = config.options;
|
|
1289
|
-
const baseUrl = opts.baseUrl;
|
|
1290
|
-
if (!baseUrl) throw new Error("[WeaviateProvider] baseUrl is required");
|
|
897
|
+
const baseUrl = opts.baseUrl || opts.url;
|
|
898
|
+
if (!baseUrl) throw new Error("[WeaviateProvider] options.baseUrl is required");
|
|
1291
899
|
this.http = import_axios7.default.create({
|
|
1292
900
|
baseURL: baseUrl,
|
|
1293
901
|
headers: __spreadValues({
|
|
@@ -1389,6 +997,160 @@ var init_WeaviateProvider = __esm({
|
|
|
1389
997
|
}
|
|
1390
998
|
});
|
|
1391
999
|
|
|
1000
|
+
// src/providers/vectordb/UniversalVectorProvider.ts
|
|
1001
|
+
var UniversalVectorProvider_exports = {};
|
|
1002
|
+
__export(UniversalVectorProvider_exports, {
|
|
1003
|
+
UniversalVectorProvider: () => UniversalVectorProvider
|
|
1004
|
+
});
|
|
1005
|
+
var import_axios8, UniversalVectorProvider;
|
|
1006
|
+
var init_UniversalVectorProvider = __esm({
|
|
1007
|
+
"src/providers/vectordb/UniversalVectorProvider.ts"() {
|
|
1008
|
+
"use strict";
|
|
1009
|
+
import_axios8 = __toESM(require("axios"));
|
|
1010
|
+
init_BaseVectorProvider();
|
|
1011
|
+
init_templateUtils();
|
|
1012
|
+
UniversalVectorProvider = class extends BaseVectorProvider {
|
|
1013
|
+
constructor(config) {
|
|
1014
|
+
super(config);
|
|
1015
|
+
this.opts = config.options;
|
|
1016
|
+
if (!this.opts.baseUrl) {
|
|
1017
|
+
throw new Error("[UniversalVectorProvider] options.baseUrl is required");
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
async initialize() {
|
|
1021
|
+
var _a;
|
|
1022
|
+
this.http = import_axios8.default.create({
|
|
1023
|
+
baseURL: this.opts.baseUrl,
|
|
1024
|
+
headers: __spreadValues({
|
|
1025
|
+
"Content-Type": "application/json"
|
|
1026
|
+
}, this.opts.headers),
|
|
1027
|
+
timeout: (_a = this.opts.timeout) != null ? _a : 3e4
|
|
1028
|
+
});
|
|
1029
|
+
if (!await this.ping()) {
|
|
1030
|
+
throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
async upsert(doc, namespace) {
|
|
1034
|
+
var _a, _b, _c;
|
|
1035
|
+
const endpoint = (_a = this.opts.upsertEndpoint) != null ? _a : "/upsert";
|
|
1036
|
+
const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
|
|
1037
|
+
id: "{{id}}",
|
|
1038
|
+
vector: "{{vector}}",
|
|
1039
|
+
content: "{{content}}",
|
|
1040
|
+
namespace: "{{namespace}}",
|
|
1041
|
+
metadata: "{{metadata}}"
|
|
1042
|
+
});
|
|
1043
|
+
const payload = buildPayload(template, {
|
|
1044
|
+
id: doc.id,
|
|
1045
|
+
vector: doc.vector,
|
|
1046
|
+
content: doc.content,
|
|
1047
|
+
namespace: namespace != null ? namespace : this.indexName,
|
|
1048
|
+
metadata: (_c = doc.metadata) != null ? _c : {}
|
|
1049
|
+
});
|
|
1050
|
+
try {
|
|
1051
|
+
await this.http.post(endpoint, payload);
|
|
1052
|
+
} catch (error) {
|
|
1053
|
+
throw new Error(
|
|
1054
|
+
`[UniversalVectorProvider] Upsert failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1055
|
+
);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
async batchUpsert(docs, namespace) {
|
|
1059
|
+
const batchSize = 50;
|
|
1060
|
+
for (let i = 0; i < docs.length; i += batchSize) {
|
|
1061
|
+
const batch = docs.slice(i, i + batchSize);
|
|
1062
|
+
await Promise.all(
|
|
1063
|
+
batch.map((doc) => this.upsert(doc, namespace))
|
|
1064
|
+
);
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1067
|
+
async query(vector, topK, namespace, filter) {
|
|
1068
|
+
var _a, _b;
|
|
1069
|
+
const endpoint = (_a = this.opts.queryEndpoint) != null ? _a : "/query";
|
|
1070
|
+
const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
|
|
1071
|
+
vector: "{{vector}}",
|
|
1072
|
+
limit: "{{topK}}",
|
|
1073
|
+
namespace: "{{namespace}}",
|
|
1074
|
+
filter: "{{filter}}"
|
|
1075
|
+
});
|
|
1076
|
+
const payload = buildPayload(template, {
|
|
1077
|
+
vector,
|
|
1078
|
+
topK,
|
|
1079
|
+
namespace: namespace != null ? namespace : this.indexName,
|
|
1080
|
+
filter: filter != null ? filter : {}
|
|
1081
|
+
});
|
|
1082
|
+
try {
|
|
1083
|
+
const response = await this.http.post(endpoint, payload);
|
|
1084
|
+
let results = response.data;
|
|
1085
|
+
if (this.opts.queryResponsePath) {
|
|
1086
|
+
results = resolvePath(response.data, this.opts.queryResponsePath);
|
|
1087
|
+
}
|
|
1088
|
+
if (!Array.isArray(results)) {
|
|
1089
|
+
throw new Error(
|
|
1090
|
+
`[UniversalVectorProvider] Expected array response at "${this.opts.queryResponsePath}", got ${typeof results}`
|
|
1091
|
+
);
|
|
1092
|
+
}
|
|
1093
|
+
return results.map((item) => {
|
|
1094
|
+
var _a2, _b2, _c, _d, _e, _f, _g;
|
|
1095
|
+
return {
|
|
1096
|
+
id: item[(_a2 = this.opts.queryIdField) != null ? _a2 : "id"],
|
|
1097
|
+
score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
|
|
1098
|
+
content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
|
|
1099
|
+
metadata: (_g = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g : {}
|
|
1100
|
+
};
|
|
1101
|
+
});
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
throw new Error(
|
|
1104
|
+
`[UniversalVectorProvider] Query failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1105
|
+
);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
async delete(id, namespace) {
|
|
1109
|
+
var _a, _b;
|
|
1110
|
+
const endpoint = (_a = this.opts.deleteEndpoint) != null ? _a : "/delete";
|
|
1111
|
+
const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
|
|
1112
|
+
id: "{{id}}",
|
|
1113
|
+
namespace: "{{namespace}}"
|
|
1114
|
+
});
|
|
1115
|
+
const payload = buildPayload(template, {
|
|
1116
|
+
id,
|
|
1117
|
+
namespace: namespace != null ? namespace : this.indexName
|
|
1118
|
+
});
|
|
1119
|
+
try {
|
|
1120
|
+
await this.http.post(endpoint, payload);
|
|
1121
|
+
} catch (error) {
|
|
1122
|
+
throw new Error(
|
|
1123
|
+
`[UniversalVectorProvider] Delete failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
async deleteNamespace(namespace) {
|
|
1128
|
+
var _a;
|
|
1129
|
+
const endpoint = (_a = this.opts.deleteNamespaceEndpoint) != null ? _a : "/delete-namespace";
|
|
1130
|
+
try {
|
|
1131
|
+
await this.http.post(endpoint, { namespace });
|
|
1132
|
+
} catch (error) {
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
`[UniversalVectorProvider] DeleteNamespace failed: ${error instanceof Error ? error.message : String(error)}`
|
|
1135
|
+
);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
async ping() {
|
|
1139
|
+
var _a;
|
|
1140
|
+
try {
|
|
1141
|
+
const endpoint = (_a = this.opts.pingEndpoint) != null ? _a : "/health";
|
|
1142
|
+
const response = await this.http.get(endpoint, { timeout: 5e3 });
|
|
1143
|
+
return response.status >= 200 && response.status < 300;
|
|
1144
|
+
} catch (e) {
|
|
1145
|
+
return false;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
async disconnect() {
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1392
1154
|
// src/handlers/index.ts
|
|
1393
1155
|
var handlers_exports = {};
|
|
1394
1156
|
__export(handlers_exports, {
|
|
@@ -1404,7 +1166,20 @@ var import_server = require("next/server");
|
|
|
1404
1166
|
init_templateUtils();
|
|
1405
1167
|
|
|
1406
1168
|
// src/config/serverConfig.ts
|
|
1407
|
-
var VECTOR_DB_PROVIDERS = [
|
|
1169
|
+
var VECTOR_DB_PROVIDERS = [
|
|
1170
|
+
"pinecone",
|
|
1171
|
+
"pgvector",
|
|
1172
|
+
"postgresql",
|
|
1173
|
+
"mongodb",
|
|
1174
|
+
"milvus",
|
|
1175
|
+
"qdrant",
|
|
1176
|
+
"chromadb",
|
|
1177
|
+
"redis",
|
|
1178
|
+
"weaviate",
|
|
1179
|
+
"rest",
|
|
1180
|
+
"universal_rest",
|
|
1181
|
+
"custom"
|
|
1182
|
+
];
|
|
1408
1183
|
var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
|
|
1409
1184
|
var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
|
|
1410
1185
|
function readString(env, name) {
|
|
@@ -1430,7 +1205,7 @@ function readEnum(env, name, fallback, allowed) {
|
|
|
1430
1205
|
throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
|
|
1431
1206
|
}
|
|
1432
1207
|
function getRagConfig(env = process.env) {
|
|
1433
|
-
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;
|
|
1208
|
+
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;
|
|
1434
1209
|
const projectId = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : "__default__";
|
|
1435
1210
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
1436
1211
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
@@ -1439,49 +1214,62 @@ function getRagConfig(env = process.env) {
|
|
|
1439
1214
|
const vectorDbOptions = {};
|
|
1440
1215
|
if (vectorProvider === "pinecone") {
|
|
1441
1216
|
vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
vectorDbOptions.connectionString = (_e = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _e : "";
|
|
1217
|
+
} else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
|
|
1218
|
+
vectorDbOptions.connectionString = (_d = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _d : "";
|
|
1445
1219
|
vectorDbOptions.dimensions = embeddingDimensions;
|
|
1220
|
+
} else if (vectorProvider === "mongodb") {
|
|
1221
|
+
vectorDbOptions.uri = (_e = readString(env, "MONGODB_URI")) != null ? _e : "";
|
|
1222
|
+
vectorDbOptions.database = (_f = readString(env, "MONGODB_DB")) != null ? _f : "";
|
|
1223
|
+
vectorDbOptions.collection = (_g = readString(env, "MONGODB_COLLECTION")) != null ? _g : "";
|
|
1224
|
+
vectorDbOptions.indexName = (_h = readString(env, "MONGODB_INDEX_NAME")) != null ? _h : "vector_index";
|
|
1225
|
+
} else if (vectorProvider === "qdrant") {
|
|
1226
|
+
vectorDbOptions.baseUrl = (_i = readString(env, "QDRANT_URL")) != null ? _i : "http://localhost:6333";
|
|
1227
|
+
vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
|
|
1228
|
+
vectorDbOptions.dimensions = embeddingDimensions;
|
|
1229
|
+
} else if (vectorProvider === "milvus") {
|
|
1230
|
+
vectorDbOptions.baseUrl = (_j = readString(env, "MILVUS_URL")) != null ? _j : "http://localhost:19530";
|
|
1231
|
+
vectorDbOptions.apiKey = readString(env, "MILVUS_API_KEY");
|
|
1232
|
+
} else if (vectorProvider === "chromadb") {
|
|
1233
|
+
vectorDbOptions.baseUrl = (_k = readString(env, "CHROMADB_URL")) != null ? _k : "http://localhost:8000";
|
|
1234
|
+
} else if (vectorProvider === "weaviate") {
|
|
1235
|
+
vectorDbOptions.baseUrl = (_l = readString(env, "WEAVIATE_URL")) != null ? _l : "http://localhost:8080";
|
|
1236
|
+
vectorDbOptions.apiKey = readString(env, "WEAVIATE_API_KEY");
|
|
1237
|
+
} else if (vectorProvider === "redis") {
|
|
1238
|
+
vectorDbOptions.baseUrl = (_m = readString(env, "REDIS_URL")) != null ? _m : "";
|
|
1239
|
+
vectorDbOptions.apiKey = readString(env, "REDIS_API_KEY");
|
|
1446
1240
|
} else if (vectorProvider === "rest") {
|
|
1447
|
-
vectorDbOptions.baseUrl = (
|
|
1241
|
+
vectorDbOptions.baseUrl = (_n = readString(env, "VECTOR_DB_REST_URL")) != null ? _n : "";
|
|
1448
1242
|
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { "api-key": readString(env, "VECTOR_DB_REST_API_KEY") } : {};
|
|
1449
1243
|
} else if (vectorProvider === "universal_rest") {
|
|
1450
|
-
vectorDbOptions.baseUrl = (
|
|
1244
|
+
vectorDbOptions.baseUrl = (_p = (_o = readString(env, "VECTOR_BASE_URL")) != null ? _o : readString(env, "VECTOR_DB_REST_URL")) != null ? _p : "";
|
|
1451
1245
|
vectorDbOptions.profile = readString(env, "VECTOR_UNIVERSAL_PROFILE");
|
|
1452
1246
|
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { Authorization: `Bearer ${readString(env, "VECTOR_DB_REST_API_KEY")}` } : {};
|
|
1453
|
-
} else if (vectorProvider === "mongodb") {
|
|
1454
|
-
vectorDbOptions.uri = (_i = readString(env, "MONGODB_URI")) != null ? _i : "";
|
|
1455
|
-
vectorDbOptions.database = (_j = readString(env, "MONGODB_DB")) != null ? _j : "";
|
|
1456
|
-
vectorDbOptions.collection = (_k = readString(env, "MONGODB_COLLECTION")) != null ? _k : "";
|
|
1457
|
-
vectorDbOptions.indexName = (_l = readString(env, "MONGODB_INDEX_NAME")) != null ? _l : "vector_index";
|
|
1458
|
-
} else if (vectorProvider === "qdrant") {
|
|
1459
|
-
vectorDbOptions.baseUrl = (_m = readString(env, "QDRANT_URL")) != null ? _m : "http://localhost:6333";
|
|
1460
|
-
vectorDbOptions.apiKey = readString(env, "QDRANT_API_KEY");
|
|
1461
|
-
vectorDbOptions.dimensions = embeddingDimensions;
|
|
1462
1247
|
}
|
|
1463
1248
|
const llmApiKeyByProvider = {
|
|
1464
1249
|
openai: readString(env, "OPENAI_API_KEY"),
|
|
1465
1250
|
anthropic: readString(env, "ANTHROPIC_API_KEY"),
|
|
1466
1251
|
ollama: void 0,
|
|
1467
|
-
universal_rest: readString(env, "LLM_API_KEY")
|
|
1252
|
+
universal_rest: readString(env, "LLM_API_KEY"),
|
|
1253
|
+
rest: readString(env, "LLM_API_KEY"),
|
|
1254
|
+
custom: readString(env, "LLM_API_KEY")
|
|
1468
1255
|
};
|
|
1469
1256
|
const embeddingApiKeyByProvider = {
|
|
1470
1257
|
openai: readString(env, "OPENAI_API_KEY"),
|
|
1471
1258
|
ollama: void 0,
|
|
1472
|
-
|
|
1259
|
+
universal_rest: (_q = readString(env, "EMBEDDING_API_KEY")) != null ? _q : readString(env, "OPENAI_API_KEY"),
|
|
1260
|
+
custom: (_r = readString(env, "EMBEDDING_API_KEY")) != null ? _r : readString(env, "OPENAI_API_KEY")
|
|
1473
1261
|
};
|
|
1474
1262
|
return {
|
|
1475
1263
|
projectId,
|
|
1476
1264
|
vectorDb: {
|
|
1477
1265
|
provider: vectorProvider,
|
|
1478
|
-
indexName: (
|
|
1266
|
+
indexName: (_s = readString(env, "VECTOR_DB_INDEX")) != null ? _s : "rag-index",
|
|
1479
1267
|
options: vectorDbOptions
|
|
1480
1268
|
},
|
|
1481
1269
|
llm: {
|
|
1482
1270
|
provider: llmProvider,
|
|
1483
|
-
model: (
|
|
1484
|
-
apiKey: (
|
|
1271
|
+
model: (_t = readString(env, "LLM_MODEL")) != null ? _t : "gpt-4o",
|
|
1272
|
+
apiKey: (_u = llmApiKeyByProvider[llmProvider]) != null ? _u : "",
|
|
1485
1273
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
1486
1274
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
1487
1275
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 1024),
|
|
@@ -1492,7 +1280,7 @@ function getRagConfig(env = process.env) {
|
|
|
1492
1280
|
},
|
|
1493
1281
|
embedding: {
|
|
1494
1282
|
provider: embeddingProvider,
|
|
1495
|
-
model: (
|
|
1283
|
+
model: (_v = readString(env, "EMBEDDING_MODEL")) != null ? _v : "text-embedding-3-small",
|
|
1496
1284
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
1497
1285
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
1498
1286
|
dimensions: embeddingDimensions,
|
|
@@ -1501,16 +1289,16 @@ function getRagConfig(env = process.env) {
|
|
|
1501
1289
|
}
|
|
1502
1290
|
},
|
|
1503
1291
|
ui: {
|
|
1504
|
-
title: (
|
|
1505
|
-
subtitle: (
|
|
1506
|
-
primaryColor: (
|
|
1507
|
-
accentColor: (
|
|
1508
|
-
logoUrl: (
|
|
1509
|
-
placeholder: (
|
|
1510
|
-
showSources: ((
|
|
1511
|
-
welcomeMessage: (
|
|
1512
|
-
visualStyle: (
|
|
1513
|
-
borderRadius: (
|
|
1292
|
+
title: (_x = (_w = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _w : readString(env, "UI_TITLE")) != null ? _x : "AI Assistant",
|
|
1293
|
+
subtitle: (_z = (_y = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _y : readString(env, "UI_SUBTITLE")) != null ? _z : "Powered by RAG",
|
|
1294
|
+
primaryColor: (_B = (_A = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _A : readString(env, "UI_PRIMARY_COLOR")) != null ? _B : "#10b981",
|
|
1295
|
+
accentColor: (_D = (_C = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _C : readString(env, "UI_ACCENT_COLOR")) != null ? _D : "#3b82f6",
|
|
1296
|
+
logoUrl: (_E = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _E : readString(env, "UI_LOGO_URL"),
|
|
1297
|
+
placeholder: (_G = (_F = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _F : readString(env, "UI_PLACEHOLDER")) != null ? _G : "Ask me anything\u2026",
|
|
1298
|
+
showSources: ((_I = (_H = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _H : readString(env, "UI_SHOW_SOURCES")) != null ? _I : "true") !== "false",
|
|
1299
|
+
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.",
|
|
1300
|
+
visualStyle: (_M = (_L = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _L : readString(env, "UI_VISUAL_STYLE")) != null ? _M : "glass",
|
|
1301
|
+
borderRadius: (_O = (_N = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _N : readString(env, "UI_BORDER_RADIUS")) != null ? _O : "xl"
|
|
1514
1302
|
},
|
|
1515
1303
|
rag: {
|
|
1516
1304
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
@@ -1586,7 +1374,7 @@ var ConfigValidator = class {
|
|
|
1586
1374
|
errors.push({
|
|
1587
1375
|
field: "embedding",
|
|
1588
1376
|
message: "Embedding config is required when using Anthropic LLM",
|
|
1589
|
-
suggestion: 'Provide embedding config with provider (e.g., "openai")',
|
|
1377
|
+
suggestion: 'Provide embedding config with provider (e.g., "openai" or "ollama")',
|
|
1590
1378
|
severity: "error"
|
|
1591
1379
|
});
|
|
1592
1380
|
}
|
|
@@ -1648,6 +1436,10 @@ var ConfigValidator = class {
|
|
|
1648
1436
|
}
|
|
1649
1437
|
return errors;
|
|
1650
1438
|
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Pinecone — only needs apiKey (environment was removed in SDK v7+).
|
|
1441
|
+
* Options key: { apiKey: string }
|
|
1442
|
+
*/
|
|
1651
1443
|
static validatePineconeConfig(config) {
|
|
1652
1444
|
const errors = [];
|
|
1653
1445
|
const opts = config.options;
|
|
@@ -1659,16 +1451,12 @@ var ConfigValidator = class {
|
|
|
1659
1451
|
severity: "error"
|
|
1660
1452
|
});
|
|
1661
1453
|
}
|
|
1662
|
-
if (!opts.environment) {
|
|
1663
|
-
errors.push({
|
|
1664
|
-
field: "vectorDb.options.environment",
|
|
1665
|
-
message: "Pinecone environment is required",
|
|
1666
|
-
suggestion: 'Set PINECONE_ENVIRONMENT environment variable (e.g., "gcp-starter")',
|
|
1667
|
-
severity: "error"
|
|
1668
|
-
});
|
|
1669
|
-
}
|
|
1670
1454
|
return errors;
|
|
1671
1455
|
}
|
|
1456
|
+
/**
|
|
1457
|
+
* PostgreSQL / pgvector — needs a connection string.
|
|
1458
|
+
* Options key: { connectionString: string }
|
|
1459
|
+
*/
|
|
1672
1460
|
static validatePostgresConfig(config) {
|
|
1673
1461
|
const errors = [];
|
|
1674
1462
|
const opts = config.options;
|
|
@@ -1682,6 +1470,10 @@ var ConfigValidator = class {
|
|
|
1682
1470
|
}
|
|
1683
1471
|
return errors;
|
|
1684
1472
|
}
|
|
1473
|
+
/**
|
|
1474
|
+
* MongoDB — needs uri, database, and collection.
|
|
1475
|
+
* Options keys: { uri: string, database: string, collection: string }
|
|
1476
|
+
*/
|
|
1685
1477
|
static validateMongoDBConfig(config) {
|
|
1686
1478
|
const errors = [];
|
|
1687
1479
|
const opts = config.options;
|
|
@@ -1711,27 +1503,30 @@ var ConfigValidator = class {
|
|
|
1711
1503
|
}
|
|
1712
1504
|
return errors;
|
|
1713
1505
|
}
|
|
1506
|
+
/**
|
|
1507
|
+
* Milvus — accepts baseUrl OR uri (preferred) OR host+port.
|
|
1508
|
+
* MilvusProvider reads opts.baseUrl ?? opts.uri.
|
|
1509
|
+
* Options keys: { baseUrl?: string, uri?: string, host?: string, port?: number }
|
|
1510
|
+
*/
|
|
1714
1511
|
static validateMilvusConfig(config) {
|
|
1715
1512
|
const errors = [];
|
|
1716
1513
|
const opts = config.options;
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
message: "Milvus host is required",
|
|
1721
|
-
suggestion: "Set MILVUS_HOST environment variable",
|
|
1722
|
-
severity: "error"
|
|
1723
|
-
});
|
|
1724
|
-
}
|
|
1725
|
-
if (!opts.port) {
|
|
1514
|
+
const hasBaseUrl = Boolean(opts.baseUrl || opts.uri);
|
|
1515
|
+
const hasHostPort = Boolean(opts.host && opts.port);
|
|
1516
|
+
if (!hasBaseUrl && !hasHostPort) {
|
|
1726
1517
|
errors.push({
|
|
1727
|
-
field: "vectorDb.options.
|
|
1728
|
-
message:
|
|
1729
|
-
suggestion: "Set
|
|
1518
|
+
field: "vectorDb.options.baseUrl",
|
|
1519
|
+
message: 'Milvus connection is required: provide baseUrl (e.g., "http://localhost:19530") or host + port',
|
|
1520
|
+
suggestion: "Set MILVUS_URL environment variable",
|
|
1730
1521
|
severity: "error"
|
|
1731
1522
|
});
|
|
1732
1523
|
}
|
|
1733
1524
|
return errors;
|
|
1734
1525
|
}
|
|
1526
|
+
/**
|
|
1527
|
+
* Qdrant — needs baseUrl (or url alias).
|
|
1528
|
+
* Options keys: { baseUrl: string, apiKey?: string }
|
|
1529
|
+
*/
|
|
1735
1530
|
static validateQdrantConfig(config) {
|
|
1736
1531
|
const errors = [];
|
|
1737
1532
|
const opts = config.options;
|
|
@@ -1745,38 +1540,55 @@ var ConfigValidator = class {
|
|
|
1745
1540
|
}
|
|
1746
1541
|
return errors;
|
|
1747
1542
|
}
|
|
1543
|
+
/**
|
|
1544
|
+
* ChromaDB — accepts baseUrl OR host.
|
|
1545
|
+
* ChromaDBProvider reads opts.baseUrl.
|
|
1546
|
+
* Options keys: { baseUrl?: string, host?: string, port?: number }
|
|
1547
|
+
*/
|
|
1748
1548
|
static validateChromaDBConfig(config) {
|
|
1749
1549
|
const errors = [];
|
|
1750
1550
|
const opts = config.options;
|
|
1751
|
-
if (!opts.
|
|
1551
|
+
if (!opts.baseUrl && !opts.host) {
|
|
1752
1552
|
errors.push({
|
|
1753
|
-
field: "vectorDb.options.
|
|
1754
|
-
message:
|
|
1755
|
-
suggestion: "Set
|
|
1553
|
+
field: "vectorDb.options.baseUrl",
|
|
1554
|
+
message: 'ChromaDB connection is required: provide baseUrl (e.g., "http://localhost:8000") or host',
|
|
1555
|
+
suggestion: "Set CHROMADB_URL environment variable",
|
|
1756
1556
|
severity: "error"
|
|
1757
1557
|
});
|
|
1758
1558
|
}
|
|
1759
1559
|
return errors;
|
|
1760
1560
|
}
|
|
1561
|
+
/**
|
|
1562
|
+
* Redis — accepts baseUrl OR url OR host+port.
|
|
1563
|
+
* RedisProvider reads opts.baseUrl.
|
|
1564
|
+
* Options keys: { baseUrl?: string, url?: string, host?: string, port?: number, apiKey?: string }
|
|
1565
|
+
*/
|
|
1761
1566
|
static validateRedisConfig(config) {
|
|
1762
1567
|
const errors = [];
|
|
1763
1568
|
const opts = config.options;
|
|
1764
|
-
|
|
1569
|
+
const hasUrl = Boolean(opts.baseUrl || opts.url);
|
|
1570
|
+
const hasHostPort = Boolean(opts.host && opts.port);
|
|
1571
|
+
if (!hasUrl && !hasHostPort) {
|
|
1765
1572
|
errors.push({
|
|
1766
|
-
field: "vectorDb.options.
|
|
1767
|
-
message: "Redis connection
|
|
1768
|
-
suggestion: "Set REDIS_URL
|
|
1573
|
+
field: "vectorDb.options.baseUrl",
|
|
1574
|
+
message: "Redis connection is required: provide baseUrl/url or host + port",
|
|
1575
|
+
suggestion: "Set REDIS_URL environment variable",
|
|
1769
1576
|
severity: "error"
|
|
1770
1577
|
});
|
|
1771
1578
|
}
|
|
1772
1579
|
return errors;
|
|
1773
1580
|
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Weaviate — accepts baseUrl OR url.
|
|
1583
|
+
* WeaviateProvider reads opts.baseUrl.
|
|
1584
|
+
* Options keys: { baseUrl?: string, url?: string, apiKey?: string }
|
|
1585
|
+
*/
|
|
1774
1586
|
static validateWeaviateConfig(config) {
|
|
1775
1587
|
const errors = [];
|
|
1776
1588
|
const opts = config.options;
|
|
1777
|
-
if (!opts.url) {
|
|
1589
|
+
if (!opts.baseUrl && !opts.url) {
|
|
1778
1590
|
errors.push({
|
|
1779
|
-
field: "vectorDb.options.
|
|
1591
|
+
field: "vectorDb.options.baseUrl",
|
|
1780
1592
|
message: "Weaviate instance URL is required",
|
|
1781
1593
|
suggestion: "Set WEAVIATE_URL environment variable",
|
|
1782
1594
|
severity: "error"
|
|
@@ -1784,6 +1596,10 @@ var ConfigValidator = class {
|
|
|
1784
1596
|
}
|
|
1785
1597
|
return errors;
|
|
1786
1598
|
}
|
|
1599
|
+
/**
|
|
1600
|
+
* Universal REST / custom REST adapter.
|
|
1601
|
+
* Options key: { baseUrl: string }
|
|
1602
|
+
*/
|
|
1787
1603
|
static validateRestConfig(config) {
|
|
1788
1604
|
const errors = [];
|
|
1789
1605
|
const opts = config.options;
|
|
@@ -1891,7 +1707,7 @@ var ConfigValidator = class {
|
|
|
1891
1707
|
errors.push({
|
|
1892
1708
|
field: "embedding.model",
|
|
1893
1709
|
message: "Embedding model name is required",
|
|
1894
|
-
suggestion: 'e.g., "text-embedding-3-small" for OpenAI',
|
|
1710
|
+
suggestion: 'e.g., "text-embedding-3-small" for OpenAI, "nomic-embed-text" for Ollama',
|
|
1895
1711
|
severity: "error"
|
|
1896
1712
|
});
|
|
1897
1713
|
}
|
|
@@ -1906,7 +1722,7 @@ var ConfigValidator = class {
|
|
|
1906
1722
|
if (config.provider === "ollama" && !config.baseUrl) {
|
|
1907
1723
|
errors.push({
|
|
1908
1724
|
field: "embedding.baseUrl",
|
|
1909
|
-
message: "Ollama base URL is required",
|
|
1725
|
+
message: "Ollama base URL is required for embedding",
|
|
1910
1726
|
suggestion: "Set EMBEDDING_BASE_URL environment variable",
|
|
1911
1727
|
severity: "error"
|
|
1912
1728
|
});
|
|
@@ -2083,17 +1899,394 @@ var DocumentChunker = class {
|
|
|
2083
1899
|
}
|
|
2084
1900
|
};
|
|
2085
1901
|
|
|
1902
|
+
// src/llm/providers/OpenAIProvider.ts
|
|
1903
|
+
var import_openai = __toESM(require("openai"));
|
|
1904
|
+
var OpenAIProvider = class {
|
|
1905
|
+
constructor(llmConfig, embeddingConfig) {
|
|
1906
|
+
if (!llmConfig.apiKey) throw new Error("[OpenAIProvider] llmConfig.apiKey is required");
|
|
1907
|
+
this.client = new import_openai.default({ apiKey: llmConfig.apiKey });
|
|
1908
|
+
this.llmConfig = llmConfig;
|
|
1909
|
+
this.embeddingConfig = embeddingConfig;
|
|
1910
|
+
}
|
|
1911
|
+
async chat(messages, context, options) {
|
|
1912
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1913
|
+
const systemContent = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
|
|
1914
|
+
|
|
1915
|
+
Context:
|
|
1916
|
+
${context}`;
|
|
1917
|
+
const systemMessage = {
|
|
1918
|
+
role: "system",
|
|
1919
|
+
content: systemContent.includes("{{context}}") ? systemContent.replace("{{context}}", context) : `${systemContent}
|
|
1920
|
+
|
|
1921
|
+
Context:
|
|
1922
|
+
${context}`
|
|
1923
|
+
};
|
|
1924
|
+
const formattedMessages = [
|
|
1925
|
+
systemMessage,
|
|
1926
|
+
...messages.map((m) => ({
|
|
1927
|
+
role: m.role,
|
|
1928
|
+
content: m.content
|
|
1929
|
+
}))
|
|
1930
|
+
];
|
|
1931
|
+
const completion = await this.client.chat.completions.create({
|
|
1932
|
+
model: this.llmConfig.model,
|
|
1933
|
+
messages: formattedMessages,
|
|
1934
|
+
max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
|
|
1935
|
+
temperature: (_e = (_d = options == null ? void 0 : options.temperature) != null ? _d : this.llmConfig.temperature) != null ? _e : 0.7,
|
|
1936
|
+
stop: options == null ? void 0 : options.stop
|
|
1937
|
+
});
|
|
1938
|
+
return (_h = (_g = (_f = completion.choices[0]) == null ? void 0 : _f.message) == null ? void 0 : _g.content) != null ? _h : "";
|
|
1939
|
+
}
|
|
1940
|
+
async embed(text, options) {
|
|
1941
|
+
const results = await this.batchEmbed([text], options);
|
|
1942
|
+
return results[0];
|
|
1943
|
+
}
|
|
1944
|
+
async batchEmbed(texts, options) {
|
|
1945
|
+
var _a, _b, _c, _d, _e;
|
|
1946
|
+
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";
|
|
1947
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
1948
|
+
const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
|
|
1949
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
1950
|
+
return response.data.map((d) => d.embedding);
|
|
1951
|
+
}
|
|
1952
|
+
async ping() {
|
|
1953
|
+
try {
|
|
1954
|
+
await this.client.models.list();
|
|
1955
|
+
return true;
|
|
1956
|
+
} catch (err) {
|
|
1957
|
+
console.error("[OpenAIProvider] Ping failed:", err);
|
|
1958
|
+
return false;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
};
|
|
1962
|
+
|
|
1963
|
+
// src/llm/providers/AnthropicProvider.ts
|
|
1964
|
+
var import_sdk = __toESM(require("@anthropic-ai/sdk"));
|
|
1965
|
+
var AnthropicProvider = class {
|
|
1966
|
+
constructor(llmConfig, embeddingConfig) {
|
|
1967
|
+
if (!llmConfig.apiKey) throw new Error("[AnthropicProvider] llmConfig.apiKey is required");
|
|
1968
|
+
this.client = new import_sdk.default({ apiKey: llmConfig.apiKey });
|
|
1969
|
+
this.llmConfig = llmConfig;
|
|
1970
|
+
this.embeddingConfig = embeddingConfig;
|
|
1971
|
+
}
|
|
1972
|
+
async chat(messages, context, options) {
|
|
1973
|
+
var _a, _b, _c;
|
|
1974
|
+
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the context below to answer the user's question accurately.
|
|
1975
|
+
|
|
1976
|
+
Context:
|
|
1977
|
+
${context}`;
|
|
1978
|
+
const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
|
|
1979
|
+
|
|
1980
|
+
Context:
|
|
1981
|
+
${context}`;
|
|
1982
|
+
const anthropicMessages = messages.map((m) => ({
|
|
1983
|
+
role: m.role === "assistant" ? "assistant" : "user",
|
|
1984
|
+
content: m.content
|
|
1985
|
+
}));
|
|
1986
|
+
const response = await this.client.messages.create({
|
|
1987
|
+
model: this.llmConfig.model,
|
|
1988
|
+
max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
|
|
1989
|
+
system,
|
|
1990
|
+
messages: anthropicMessages
|
|
1991
|
+
});
|
|
1992
|
+
const block = response.content[0];
|
|
1993
|
+
return block.type === "text" ? block.text : "";
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Anthropic does not offer an embedding API.
|
|
1997
|
+
* This method throws with a clear error so developers know to configure
|
|
1998
|
+
* a separate embedding provider (OpenAI or Ollama).
|
|
1999
|
+
*/
|
|
2000
|
+
async embed(text, options) {
|
|
2001
|
+
void text;
|
|
2002
|
+
void options;
|
|
2003
|
+
throw new Error(
|
|
2004
|
+
'[AnthropicProvider] Anthropic does not provide an embedding API. Set embedding.provider to "openai" or "ollama" in your RagConfig.'
|
|
2005
|
+
);
|
|
2006
|
+
}
|
|
2007
|
+
async batchEmbed(texts, options) {
|
|
2008
|
+
void texts;
|
|
2009
|
+
void options;
|
|
2010
|
+
throw new Error(
|
|
2011
|
+
"[AnthropicProvider] Anthropic does not provide an embedding API."
|
|
2012
|
+
);
|
|
2013
|
+
}
|
|
2014
|
+
async ping() {
|
|
2015
|
+
try {
|
|
2016
|
+
await this.client.models.list();
|
|
2017
|
+
return true;
|
|
2018
|
+
} catch (err) {
|
|
2019
|
+
console.error("[AnthropicProvider] Ping failed:", err);
|
|
2020
|
+
return false;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
};
|
|
2024
|
+
|
|
2025
|
+
// src/llm/providers/OllamaProvider.ts
|
|
2026
|
+
var import_axios = __toESM(require("axios"));
|
|
2027
|
+
var OllamaProvider = class {
|
|
2028
|
+
constructor(llmConfig, embeddingConfig) {
|
|
2029
|
+
var _a;
|
|
2030
|
+
const baseURL = (_a = llmConfig.baseUrl) != null ? _a : "http://localhost:11434";
|
|
2031
|
+
this.http = import_axios.default.create({ baseURL, timeout: 12e4 });
|
|
2032
|
+
this.llmConfig = llmConfig;
|
|
2033
|
+
this.embeddingConfig = embeddingConfig;
|
|
2034
|
+
}
|
|
2035
|
+
async chat(messages, context, options) {
|
|
2036
|
+
var _a, _b, _c, _d, _e;
|
|
2037
|
+
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the provided context to answer the user's question.
|
|
2038
|
+
|
|
2039
|
+
Context:
|
|
2040
|
+
${context}`;
|
|
2041
|
+
const system = systemPrompt.includes("{{context}}") ? systemPrompt.replace("{{context}}", context) : `${systemPrompt}
|
|
2042
|
+
|
|
2043
|
+
Context:
|
|
2044
|
+
${context}`;
|
|
2045
|
+
const { data } = await this.http.post("/api/chat", {
|
|
2046
|
+
model: this.llmConfig.model,
|
|
2047
|
+
stream: false,
|
|
2048
|
+
options: {
|
|
2049
|
+
temperature: (_c = (_b = options == null ? void 0 : options.temperature) != null ? _b : this.llmConfig.temperature) != null ? _c : 0.7,
|
|
2050
|
+
num_predict: (_e = (_d = options == null ? void 0 : options.maxTokens) != null ? _d : this.llmConfig.maxTokens) != null ? _e : 1024
|
|
2051
|
+
},
|
|
2052
|
+
messages: [
|
|
2053
|
+
{ role: "system", content: system },
|
|
2054
|
+
...messages.map((m) => ({ role: m.role, content: m.content }))
|
|
2055
|
+
]
|
|
2056
|
+
});
|
|
2057
|
+
return data.message.content;
|
|
2058
|
+
}
|
|
2059
|
+
async embed(text, options) {
|
|
2060
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2061
|
+
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";
|
|
2062
|
+
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2063
|
+
const client = baseURL !== ((_g = this.llmConfig.baseUrl) != null ? _g : "http://localhost:11434") ? import_axios.default.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2064
|
+
const { data } = await client.post("/api/embeddings", {
|
|
2065
|
+
model,
|
|
2066
|
+
prompt: text
|
|
2067
|
+
});
|
|
2068
|
+
return data.embedding;
|
|
2069
|
+
}
|
|
2070
|
+
async batchEmbed(texts, options) {
|
|
2071
|
+
const vectors = [];
|
|
2072
|
+
for (const text of texts) {
|
|
2073
|
+
vectors.push(await this.embed(text, options));
|
|
2074
|
+
}
|
|
2075
|
+
return vectors;
|
|
2076
|
+
}
|
|
2077
|
+
async ping() {
|
|
2078
|
+
try {
|
|
2079
|
+
await this.http.get("/api/tags");
|
|
2080
|
+
return true;
|
|
2081
|
+
} catch (err) {
|
|
2082
|
+
console.error("[OllamaProvider] Ping failed:", err);
|
|
2083
|
+
return false;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
};
|
|
2087
|
+
|
|
2088
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
2089
|
+
var import_axios2 = __toESM(require("axios"));
|
|
2090
|
+
init_templateUtils();
|
|
2091
|
+
|
|
2092
|
+
// src/config/UniversalProfiles.ts
|
|
2093
|
+
var OPENAI_BASE = {
|
|
2094
|
+
chatPath: "/chat/completions",
|
|
2095
|
+
embedPath: "/embeddings",
|
|
2096
|
+
responseExtractPath: "choices[0].message.content",
|
|
2097
|
+
embedExtractPath: "data[0].embedding",
|
|
2098
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
2099
|
+
};
|
|
2100
|
+
var LLM_PROFILES = {
|
|
2101
|
+
"openai-compatible": OPENAI_BASE,
|
|
2102
|
+
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
2103
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
2104
|
+
}),
|
|
2105
|
+
"anthropic-claude": {
|
|
2106
|
+
chatPath: "/v1/messages",
|
|
2107
|
+
responseExtractPath: "content[0].text",
|
|
2108
|
+
headers: { "anthropic-version": "2023-06-01" },
|
|
2109
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
2110
|
+
},
|
|
2111
|
+
"google-gemini": {
|
|
2112
|
+
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
2113
|
+
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
2114
|
+
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
2115
|
+
},
|
|
2116
|
+
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
2117
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
2118
|
+
}),
|
|
2119
|
+
"ollama-standard": {
|
|
2120
|
+
chatPath: "/api/chat",
|
|
2121
|
+
embedPath: "/api/embeddings",
|
|
2122
|
+
responseExtractPath: "message.content",
|
|
2123
|
+
embedExtractPath: "embedding",
|
|
2124
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
2125
|
+
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
|
|
2129
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
2130
|
+
var UniversalLLMAdapter = class {
|
|
2131
|
+
constructor(config) {
|
|
2132
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2133
|
+
this.model = config.model;
|
|
2134
|
+
const llmConfig = config;
|
|
2135
|
+
const options = (_a = llmConfig.options) != null ? _a : {};
|
|
2136
|
+
let profile = {};
|
|
2137
|
+
if (typeof options.profile === "string") {
|
|
2138
|
+
profile = LLM_PROFILES[options.profile] || {};
|
|
2139
|
+
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
2140
|
+
profile = options.profile;
|
|
2141
|
+
}
|
|
2142
|
+
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
2143
|
+
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
2144
|
+
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
2145
|
+
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
2146
|
+
const baseUrl = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl;
|
|
2147
|
+
if (!baseUrl) {
|
|
2148
|
+
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
2149
|
+
}
|
|
2150
|
+
this.http = import_axios2.default.create({
|
|
2151
|
+
baseURL: baseUrl,
|
|
2152
|
+
headers: __spreadValues(__spreadValues({
|
|
2153
|
+
"Content-Type": "application/json"
|
|
2154
|
+
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {}),
|
|
2155
|
+
timeout: (_g = this.opts.timeout) != null ? _g : 6e4
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
async chat(messages, context) {
|
|
2159
|
+
var _a, _b;
|
|
2160
|
+
const path = (_a = this.opts.chatPath) != null ? _a : "/chat/completions";
|
|
2161
|
+
const formattedMessages = [
|
|
2162
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
2163
|
+
|
|
2164
|
+
Context:
|
|
2165
|
+
${context != null ? context : "None"}` },
|
|
2166
|
+
...messages
|
|
2167
|
+
];
|
|
2168
|
+
let payload;
|
|
2169
|
+
if (this.opts.chatPayloadTemplate) {
|
|
2170
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
2171
|
+
model: this.model,
|
|
2172
|
+
messages: formattedMessages,
|
|
2173
|
+
maxTokens: this.maxTokens,
|
|
2174
|
+
temperature: this.temperature
|
|
2175
|
+
});
|
|
2176
|
+
} else {
|
|
2177
|
+
payload = {
|
|
2178
|
+
model: this.model,
|
|
2179
|
+
messages: formattedMessages,
|
|
2180
|
+
max_tokens: this.maxTokens,
|
|
2181
|
+
temperature: this.temperature
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
const { data } = await this.http.post(path, payload);
|
|
2185
|
+
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
2186
|
+
const result = resolvePath(data, extractPath);
|
|
2187
|
+
if (result === void 0) {
|
|
2188
|
+
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
2189
|
+
}
|
|
2190
|
+
return String(result);
|
|
2191
|
+
}
|
|
2192
|
+
async embed(text) {
|
|
2193
|
+
var _a, _b;
|
|
2194
|
+
const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
|
|
2195
|
+
let payload;
|
|
2196
|
+
if (this.opts.embedPayloadTemplate) {
|
|
2197
|
+
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
2198
|
+
model: this.model,
|
|
2199
|
+
input: text
|
|
2200
|
+
});
|
|
2201
|
+
} else {
|
|
2202
|
+
payload = {
|
|
2203
|
+
model: this.model,
|
|
2204
|
+
input: text
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2207
|
+
const { data } = await this.http.post(path, payload);
|
|
2208
|
+
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
2209
|
+
const vector = resolvePath(data, extractPath);
|
|
2210
|
+
if (!Array.isArray(vector)) {
|
|
2211
|
+
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
2212
|
+
}
|
|
2213
|
+
return vector;
|
|
2214
|
+
}
|
|
2215
|
+
async batchEmbed(texts) {
|
|
2216
|
+
const vectors = [];
|
|
2217
|
+
for (const text of texts) {
|
|
2218
|
+
vectors.push(await this.embed(text));
|
|
2219
|
+
}
|
|
2220
|
+
return vectors;
|
|
2221
|
+
}
|
|
2222
|
+
async ping() {
|
|
2223
|
+
try {
|
|
2224
|
+
if (this.opts.pingPath) {
|
|
2225
|
+
await this.http.get(this.opts.pingPath);
|
|
2226
|
+
}
|
|
2227
|
+
return true;
|
|
2228
|
+
} catch (err) {
|
|
2229
|
+
console.error("[UniversalLLMAdapter] Ping failed:", err);
|
|
2230
|
+
return false;
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
};
|
|
2234
|
+
|
|
2235
|
+
// src/llm/LLMFactory.ts
|
|
2236
|
+
var LLMFactory = class _LLMFactory {
|
|
2237
|
+
static create(llmConfig, embeddingConfig) {
|
|
2238
|
+
var _a;
|
|
2239
|
+
switch (llmConfig.provider) {
|
|
2240
|
+
case "openai":
|
|
2241
|
+
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
2242
|
+
case "anthropic":
|
|
2243
|
+
return new AnthropicProvider(llmConfig, embeddingConfig);
|
|
2244
|
+
case "ollama":
|
|
2245
|
+
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
2246
|
+
case "rest":
|
|
2247
|
+
case "universal_rest":
|
|
2248
|
+
case "custom":
|
|
2249
|
+
return new UniversalLLMAdapter(llmConfig);
|
|
2250
|
+
default:
|
|
2251
|
+
if (llmConfig.baseUrl || ((_a = llmConfig.options) == null ? void 0 : _a.baseUrl)) {
|
|
2252
|
+
return new UniversalLLMAdapter(llmConfig);
|
|
2253
|
+
}
|
|
2254
|
+
throw new Error(
|
|
2255
|
+
`[LLMFactory] Unknown provider "${llmConfig.provider}". Supported: openai | anthropic | ollama | rest | custom`
|
|
2256
|
+
);
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
/**
|
|
2260
|
+
* Creates a dedicated embedding-only provider.
|
|
2261
|
+
* Useful when the LLM provider (e.g. Anthropic) doesn't support embeddings.
|
|
2262
|
+
*/
|
|
2263
|
+
static createEmbeddingProvider(embeddingConfig) {
|
|
2264
|
+
const fakeLLMConfig = {
|
|
2265
|
+
provider: embeddingConfig.provider,
|
|
2266
|
+
model: embeddingConfig.model,
|
|
2267
|
+
apiKey: embeddingConfig.apiKey,
|
|
2268
|
+
baseUrl: embeddingConfig.baseUrl,
|
|
2269
|
+
options: embeddingConfig.options
|
|
2270
|
+
};
|
|
2271
|
+
return _LLMFactory.create(fakeLLMConfig, embeddingConfig);
|
|
2272
|
+
}
|
|
2273
|
+
};
|
|
2274
|
+
|
|
2086
2275
|
// src/core/ProviderRegistry.ts
|
|
2087
|
-
init_LLMFactory();
|
|
2088
2276
|
var ProviderRegistry = class {
|
|
2089
2277
|
/**
|
|
2090
|
-
* Register a custom vector provider.
|
|
2278
|
+
* Register a custom vector provider class by name.
|
|
2279
|
+
* The name must match the provider value used in VectorDBConfig.provider.
|
|
2280
|
+
*
|
|
2281
|
+
* @example
|
|
2282
|
+
* ProviderRegistry.registerVectorProvider('my-db', MyCustomProvider);
|
|
2091
2283
|
*/
|
|
2092
2284
|
static registerVectorProvider(name, providerClass) {
|
|
2093
2285
|
this.vectorProviders[name] = providerClass;
|
|
2094
2286
|
}
|
|
2095
2287
|
/**
|
|
2096
2288
|
* Creates a vector database provider based on the configuration.
|
|
2289
|
+
* Built-in providers are dynamically imported to avoid bundling all SDKs.
|
|
2097
2290
|
*/
|
|
2098
2291
|
static async createVectorProvider(config) {
|
|
2099
2292
|
const { provider } = config;
|
|
@@ -2101,33 +2294,48 @@ var ProviderRegistry = class {
|
|
|
2101
2294
|
return new this.vectorProviders[provider](config);
|
|
2102
2295
|
}
|
|
2103
2296
|
switch (provider) {
|
|
2104
|
-
case "pinecone":
|
|
2297
|
+
case "pinecone": {
|
|
2105
2298
|
const { PineconeProvider: PineconeProvider2 } = await Promise.resolve().then(() => (init_PineconeProvider(), PineconeProvider_exports));
|
|
2106
2299
|
return new PineconeProvider2(config);
|
|
2300
|
+
}
|
|
2107
2301
|
case "pgvector":
|
|
2108
|
-
case "postgresql":
|
|
2302
|
+
case "postgresql": {
|
|
2109
2303
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
2110
2304
|
return new PostgreSQLProvider2(config);
|
|
2111
|
-
|
|
2305
|
+
}
|
|
2306
|
+
case "mongodb": {
|
|
2112
2307
|
const { MongoDBProvider: MongoDBProvider2 } = await Promise.resolve().then(() => (init_MongoDBProvider(), MongoDBProvider_exports));
|
|
2113
2308
|
return new MongoDBProvider2(config);
|
|
2114
|
-
|
|
2309
|
+
}
|
|
2310
|
+
case "milvus": {
|
|
2115
2311
|
const { MilvusProvider: MilvusProvider2 } = await Promise.resolve().then(() => (init_MilvusProvider(), MilvusProvider_exports));
|
|
2116
2312
|
return new MilvusProvider2(config);
|
|
2117
|
-
|
|
2313
|
+
}
|
|
2314
|
+
case "qdrant": {
|
|
2118
2315
|
const { QdrantProvider: QdrantProvider2 } = await Promise.resolve().then(() => (init_QdrantProvider(), QdrantProvider_exports));
|
|
2119
2316
|
return new QdrantProvider2(config);
|
|
2120
|
-
|
|
2317
|
+
}
|
|
2318
|
+
case "chromadb": {
|
|
2121
2319
|
const { ChromaDBProvider: ChromaDBProvider2 } = await Promise.resolve().then(() => (init_ChromaDBProvider(), ChromaDBProvider_exports));
|
|
2122
2320
|
return new ChromaDBProvider2(config);
|
|
2123
|
-
|
|
2321
|
+
}
|
|
2322
|
+
case "redis": {
|
|
2124
2323
|
const { RedisProvider: RedisProvider2 } = await Promise.resolve().then(() => (init_RedisProvider(), RedisProvider_exports));
|
|
2125
2324
|
return new RedisProvider2(config);
|
|
2126
|
-
|
|
2325
|
+
}
|
|
2326
|
+
case "weaviate": {
|
|
2127
2327
|
const { WeaviateProvider: WeaviateProvider2 } = await Promise.resolve().then(() => (init_WeaviateProvider(), WeaviateProvider_exports));
|
|
2128
2328
|
return new WeaviateProvider2(config);
|
|
2329
|
+
}
|
|
2330
|
+
case "universal_rest":
|
|
2331
|
+
case "rest": {
|
|
2332
|
+
const { UniversalVectorProvider: UniversalVectorProvider2 } = await Promise.resolve().then(() => (init_UniversalVectorProvider(), UniversalVectorProvider_exports));
|
|
2333
|
+
return new UniversalVectorProvider2(config);
|
|
2334
|
+
}
|
|
2129
2335
|
default:
|
|
2130
|
-
throw new Error(
|
|
2336
|
+
throw new Error(
|
|
2337
|
+
`[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).`
|
|
2338
|
+
);
|
|
2131
2339
|
}
|
|
2132
2340
|
}
|
|
2133
2341
|
/**
|
|
@@ -2363,6 +2571,83 @@ ${errorMessages}`
|
|
|
2363
2571
|
}
|
|
2364
2572
|
};
|
|
2365
2573
|
|
|
2574
|
+
// src/config/EmbeddingStrategy.ts
|
|
2575
|
+
var EmbeddingStrategyResolver = class {
|
|
2576
|
+
/**
|
|
2577
|
+
* Determine strategy based on LLM and embedding configs
|
|
2578
|
+
*/
|
|
2579
|
+
static determineStrategy(llmConfig, embeddingConfig) {
|
|
2580
|
+
if (!embeddingConfig) {
|
|
2581
|
+
return this.supportsEmbedding(llmConfig.provider) ? "integrated" /* INTEGRATED */ : "separate" /* SEPARATE */;
|
|
2582
|
+
}
|
|
2583
|
+
if (embeddingConfig.provider !== llmConfig.provider) {
|
|
2584
|
+
return "separate" /* SEPARATE */;
|
|
2585
|
+
}
|
|
2586
|
+
if (embeddingConfig.model !== llmConfig.model) {
|
|
2587
|
+
return "external" /* EXTERNAL */;
|
|
2588
|
+
}
|
|
2589
|
+
return "integrated" /* INTEGRATED */;
|
|
2590
|
+
}
|
|
2591
|
+
/**
|
|
2592
|
+
* Resolve and initialize providers according to the strategy
|
|
2593
|
+
*/
|
|
2594
|
+
static async resolve(llmConfig, embeddingConfig) {
|
|
2595
|
+
const strategy = this.determineStrategy(llmConfig, embeddingConfig);
|
|
2596
|
+
const llmProvider = LLMFactory.create(llmConfig, embeddingConfig);
|
|
2597
|
+
let embeddingProvider;
|
|
2598
|
+
switch (strategy) {
|
|
2599
|
+
case "integrated" /* INTEGRATED */:
|
|
2600
|
+
embeddingProvider = llmProvider;
|
|
2601
|
+
break;
|
|
2602
|
+
case "separate" /* SEPARATE */:
|
|
2603
|
+
if (!embeddingConfig) {
|
|
2604
|
+
throw new Error(
|
|
2605
|
+
"[EmbeddingStrategyResolver] SEPARATE strategy requires embeddingConfig"
|
|
2606
|
+
);
|
|
2607
|
+
}
|
|
2608
|
+
embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
|
|
2609
|
+
break;
|
|
2610
|
+
case "external" /* EXTERNAL */:
|
|
2611
|
+
if (!embeddingConfig) {
|
|
2612
|
+
throw new Error(
|
|
2613
|
+
"[EmbeddingStrategyResolver] EXTERNAL strategy requires embeddingConfig"
|
|
2614
|
+
);
|
|
2615
|
+
}
|
|
2616
|
+
embeddingProvider = LLMFactory.createEmbeddingProvider(embeddingConfig);
|
|
2617
|
+
break;
|
|
2618
|
+
default:
|
|
2619
|
+
throw new Error(`[EmbeddingStrategyResolver] Unknown strategy: ${strategy}`);
|
|
2620
|
+
}
|
|
2621
|
+
return {
|
|
2622
|
+
strategy,
|
|
2623
|
+
embeddingProvider,
|
|
2624
|
+
llmProvider
|
|
2625
|
+
};
|
|
2626
|
+
}
|
|
2627
|
+
/**
|
|
2628
|
+
* Check if an LLM provider natively supports embeddings
|
|
2629
|
+
*/
|
|
2630
|
+
static supportsEmbedding(provider) {
|
|
2631
|
+
const providersWithEmbedding = ["openai", "ollama", "rest", "universal_rest"];
|
|
2632
|
+
return providersWithEmbedding.includes(provider);
|
|
2633
|
+
}
|
|
2634
|
+
/**
|
|
2635
|
+
* Get a human-readable description of the strategy
|
|
2636
|
+
*/
|
|
2637
|
+
static getDescription(strategy) {
|
|
2638
|
+
switch (strategy) {
|
|
2639
|
+
case "integrated" /* INTEGRATED */:
|
|
2640
|
+
return "Using LLM provider for both chat and embeddings";
|
|
2641
|
+
case "separate" /* SEPARATE */:
|
|
2642
|
+
return "Using separate embedding provider";
|
|
2643
|
+
case "external" /* EXTERNAL */:
|
|
2644
|
+
return "Using external embedding service";
|
|
2645
|
+
default:
|
|
2646
|
+
return "Unknown strategy";
|
|
2647
|
+
}
|
|
2648
|
+
}
|
|
2649
|
+
};
|
|
2650
|
+
|
|
2366
2651
|
// src/core/Pipeline.ts
|
|
2367
2652
|
var Pipeline = class {
|
|
2368
2653
|
constructor(config) {
|
|
@@ -2377,18 +2662,17 @@ var Pipeline = class {
|
|
|
2377
2662
|
async initialize() {
|
|
2378
2663
|
if (this.initialised) return;
|
|
2379
2664
|
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
}
|
|
2665
|
+
const { llmProvider, embeddingProvider } = await EmbeddingStrategyResolver.resolve(
|
|
2666
|
+
this.config.llm,
|
|
2667
|
+
this.config.embedding
|
|
2668
|
+
);
|
|
2669
|
+
this.llmProvider = llmProvider;
|
|
2670
|
+
this.embeddingProvider = embeddingProvider;
|
|
2387
2671
|
await this.vectorDB.initialize();
|
|
2388
2672
|
this.initialised = true;
|
|
2389
2673
|
}
|
|
2390
2674
|
/**
|
|
2391
|
-
* Ingest documents with automatic chunking, embedding, and batch
|
|
2675
|
+
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
2392
2676
|
* Handles retries for transient failures.
|
|
2393
2677
|
*/
|
|
2394
2678
|
async ingest(documents, namespace) {
|
|
@@ -2401,19 +2685,18 @@ var Pipeline = class {
|
|
|
2401
2685
|
docId: doc.docId,
|
|
2402
2686
|
metadata: doc.metadata
|
|
2403
2687
|
});
|
|
2404
|
-
const
|
|
2688
|
+
const embedBatchOptions = {
|
|
2405
2689
|
batchSize: 50,
|
|
2406
|
-
// Embedding batch size
|
|
2407
2690
|
maxRetries: 3,
|
|
2408
2691
|
initialDelayMs: 100
|
|
2409
2692
|
};
|
|
2410
2693
|
const vectors = await BatchProcessor.mapWithRetry(
|
|
2411
2694
|
chunks.map((c) => c.content),
|
|
2412
2695
|
(text) => this.embeddingProvider.embed(text),
|
|
2413
|
-
|
|
2696
|
+
embedBatchOptions
|
|
2414
2697
|
);
|
|
2415
2698
|
if (vectors.length !== chunks.length) {
|
|
2416
|
-
throw new Error(`Embedding
|
|
2699
|
+
throw new Error(`Embedding mismatch: got ${vectors.length} vectors for ${chunks.length} chunks`);
|
|
2417
2700
|
}
|
|
2418
2701
|
const upsertDocs = chunks.map((chunk, i) => ({
|
|
2419
2702
|
id: chunk.id,
|
|
@@ -2440,10 +2723,7 @@ var Pipeline = class {
|
|
|
2440
2723
|
});
|
|
2441
2724
|
} catch (error) {
|
|
2442
2725
|
console.error(`[Pipeline] Failed to ingest document ${doc.docId}:`, error);
|
|
2443
|
-
results.push({
|
|
2444
|
-
docId: doc.docId,
|
|
2445
|
-
chunksIngested: 0
|
|
2446
|
-
});
|
|
2726
|
+
results.push({ docId: doc.docId, chunksIngested: 0 });
|
|
2447
2727
|
}
|
|
2448
2728
|
}
|
|
2449
2729
|
return results;
|
|
@@ -2473,7 +2753,6 @@ ${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
|
2473
2753
|
var ProviderHealthCheck = class {
|
|
2474
2754
|
/**
|
|
2475
2755
|
* Validates vector database configuration before initialization.
|
|
2476
|
-
* Performs connectivity checks and verifies required resources exist.
|
|
2477
2756
|
*/
|
|
2478
2757
|
static async checkVectorProvider(config) {
|
|
2479
2758
|
const timestamp = Date.now();
|
|
@@ -2481,7 +2760,6 @@ var ProviderHealthCheck = class {
|
|
|
2481
2760
|
projectId: "health-check",
|
|
2482
2761
|
vectorDb: config,
|
|
2483
2762
|
llm: { provider: "openai", model: "gpt-4o" },
|
|
2484
|
-
// dummy
|
|
2485
2763
|
embedding: { provider: "openai", model: "text-embedding-3-small" }
|
|
2486
2764
|
});
|
|
2487
2765
|
const vectorDbErrors = configErrors.filter((e) => e.field.startsWith("vectorDb"));
|
|
@@ -2551,10 +2829,7 @@ var ProviderHealthCheck = class {
|
|
|
2551
2829
|
return {
|
|
2552
2830
|
healthy: true,
|
|
2553
2831
|
provider: "pinecone",
|
|
2554
|
-
capabilities: {
|
|
2555
|
-
indexes: indexNames.length,
|
|
2556
|
-
targetIndex: config.indexName
|
|
2557
|
-
},
|
|
2832
|
+
capabilities: { indexes: indexNames.length, targetIndex: config.indexName },
|
|
2558
2833
|
timestamp
|
|
2559
2834
|
};
|
|
2560
2835
|
} catch (error) {
|
|
@@ -2573,9 +2848,7 @@ var ProviderHealthCheck = class {
|
|
|
2573
2848
|
const client = new Client({ connectionString: opts.connectionString });
|
|
2574
2849
|
await client.connect();
|
|
2575
2850
|
const result = await client.query(`
|
|
2576
|
-
SELECT EXISTS(
|
|
2577
|
-
SELECT 1 FROM pg_extension WHERE extname = 'vector'
|
|
2578
|
-
);
|
|
2851
|
+
SELECT EXISTS(SELECT 1 FROM pg_extension WHERE extname = 'vector');
|
|
2579
2852
|
`);
|
|
2580
2853
|
const hasVector = result.rows[0].exists;
|
|
2581
2854
|
await client.end();
|
|
@@ -2610,7 +2883,7 @@ var ProviderHealthCheck = class {
|
|
|
2610
2883
|
provider: "mongodb",
|
|
2611
2884
|
capabilities: {
|
|
2612
2885
|
collections: collectionNames.length,
|
|
2613
|
-
targetCollection: hasCollection ? opts.collection : "NOT FOUND"
|
|
2886
|
+
targetCollection: hasCollection ? opts.collection : "NOT FOUND (will be created on first insert)"
|
|
2614
2887
|
},
|
|
2615
2888
|
timestamp
|
|
2616
2889
|
};
|
|
@@ -2623,16 +2896,16 @@ var ProviderHealthCheck = class {
|
|
|
2623
2896
|
};
|
|
2624
2897
|
}
|
|
2625
2898
|
}
|
|
2899
|
+
/**
|
|
2900
|
+
* Milvus health check — uses baseUrl/uri (matching MilvusProvider constructor).
|
|
2901
|
+
*/
|
|
2626
2902
|
static async checkMilvus(config, timestamp) {
|
|
2627
2903
|
const opts = config.options;
|
|
2628
|
-
const
|
|
2629
|
-
const port = opts.port || 19530;
|
|
2904
|
+
const baseUrl = opts.baseUrl || opts.uri || (opts.host ? `http://${opts.host}:${opts.port || 19530}` : "http://localhost:19530");
|
|
2630
2905
|
try {
|
|
2631
2906
|
const controller = new AbortController();
|
|
2632
2907
|
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
2633
|
-
const response = await fetch(
|
|
2634
|
-
signal: controller.signal
|
|
2635
|
-
});
|
|
2908
|
+
const response = await fetch(`${baseUrl}/v1/health`, { signal: controller.signal });
|
|
2636
2909
|
clearTimeout(timeoutId);
|
|
2637
2910
|
if (!response.ok) {
|
|
2638
2911
|
throw new Error(`Health check returned ${response.status}`);
|
|
@@ -2640,7 +2913,7 @@ var ProviderHealthCheck = class {
|
|
|
2640
2913
|
return {
|
|
2641
2914
|
healthy: true,
|
|
2642
2915
|
provider: "milvus",
|
|
2643
|
-
capabilities: { endpoint:
|
|
2916
|
+
capabilities: { endpoint: baseUrl },
|
|
2644
2917
|
timestamp
|
|
2645
2918
|
};
|
|
2646
2919
|
} catch (error) {
|
|
@@ -2652,17 +2925,18 @@ var ProviderHealthCheck = class {
|
|
|
2652
2925
|
};
|
|
2653
2926
|
}
|
|
2654
2927
|
}
|
|
2928
|
+
/**
|
|
2929
|
+
* Qdrant health check — uses baseUrl (matching QdrantProvider constructor).
|
|
2930
|
+
*/
|
|
2655
2931
|
static async checkQdrant(config, timestamp) {
|
|
2656
2932
|
const opts = config.options;
|
|
2657
|
-
const baseUrl = opts.baseUrl || opts.url || "http://localhost:6333";
|
|
2933
|
+
const baseUrl = (opts.baseUrl || opts.url || "http://localhost:6333").replace(/\/$/, "");
|
|
2658
2934
|
try {
|
|
2659
2935
|
const apiKey = opts.apiKey;
|
|
2660
2936
|
const response = await fetch(`${baseUrl}/`, {
|
|
2661
2937
|
headers: apiKey ? { "api-key": apiKey } : {}
|
|
2662
2938
|
});
|
|
2663
|
-
if (!response.ok) {
|
|
2664
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
2665
|
-
}
|
|
2939
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
2666
2940
|
const health = await response.json();
|
|
2667
2941
|
return {
|
|
2668
2942
|
healthy: true,
|
|
@@ -2679,19 +2953,19 @@ var ProviderHealthCheck = class {
|
|
|
2679
2953
|
};
|
|
2680
2954
|
}
|
|
2681
2955
|
}
|
|
2956
|
+
/**
|
|
2957
|
+
* ChromaDB health check — uses baseUrl/host (matching ChromaDBProvider constructor).
|
|
2958
|
+
*/
|
|
2682
2959
|
static async checkChromaDB(config, timestamp) {
|
|
2683
2960
|
const opts = config.options;
|
|
2684
|
-
const
|
|
2685
|
-
const port = opts.port || 8e3;
|
|
2961
|
+
const baseUrl = opts.baseUrl || (opts.host ? `http://${opts.host}:${opts.port || 8e3}` : "http://localhost:8000");
|
|
2686
2962
|
try {
|
|
2687
|
-
const response = await fetch(
|
|
2688
|
-
if (!response.ok) {
|
|
2689
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
2690
|
-
}
|
|
2963
|
+
const response = await fetch(`${baseUrl}/api/v1/heartbeat`);
|
|
2964
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
2691
2965
|
return {
|
|
2692
2966
|
healthy: true,
|
|
2693
2967
|
provider: "chromadb",
|
|
2694
|
-
capabilities: { endpoint:
|
|
2968
|
+
capabilities: { endpoint: baseUrl },
|
|
2695
2969
|
timestamp
|
|
2696
2970
|
};
|
|
2697
2971
|
} catch (error) {
|
|
@@ -2703,38 +2977,43 @@ var ProviderHealthCheck = class {
|
|
|
2703
2977
|
};
|
|
2704
2978
|
}
|
|
2705
2979
|
}
|
|
2980
|
+
/**
|
|
2981
|
+
* Redis health check — Redis is TCP-only (no HTTP endpoint).
|
|
2982
|
+
* We report healthy=true with a note; actual connectivity is validated at first operation.
|
|
2983
|
+
*/
|
|
2706
2984
|
static async checkRedis(config, timestamp) {
|
|
2707
2985
|
const opts = config.options;
|
|
2708
|
-
const url = opts.url || `redis://${opts.host}:${opts.port}
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
healthy: true,
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
timestamp
|
|
2716
|
-
};
|
|
2717
|
-
} catch (error) {
|
|
2718
|
-
return {
|
|
2719
|
-
healthy: false,
|
|
2720
|
-
provider: "redis",
|
|
2721
|
-
error: `Connection check failed: ${error instanceof Error ? error.message : String(error)}. Ensure Redis is running at ${url}`,
|
|
2722
|
-
timestamp
|
|
2723
|
-
};
|
|
2986
|
+
const url = opts.baseUrl || opts.url || (opts.host && opts.port ? `redis://${opts.host}:${opts.port}` : "redis://localhost:6379");
|
|
2987
|
+
if (url.startsWith("http")) {
|
|
2988
|
+
try {
|
|
2989
|
+
await fetch(url);
|
|
2990
|
+
return { healthy: true, provider: "redis", capabilities: { endpoint: url }, timestamp };
|
|
2991
|
+
} catch (e) {
|
|
2992
|
+
}
|
|
2724
2993
|
}
|
|
2994
|
+
return {
|
|
2995
|
+
healthy: true,
|
|
2996
|
+
provider: "redis",
|
|
2997
|
+
capabilities: {
|
|
2998
|
+
endpoint: url,
|
|
2999
|
+
note: "Redis uses TCP; connectivity is validated on first operation."
|
|
3000
|
+
},
|
|
3001
|
+
timestamp
|
|
3002
|
+
};
|
|
2725
3003
|
}
|
|
3004
|
+
/**
|
|
3005
|
+
* Weaviate health check — uses baseUrl/url (matching WeaviateProvider constructor).
|
|
3006
|
+
*/
|
|
2726
3007
|
static async checkWeaviate(config, timestamp) {
|
|
2727
3008
|
const opts = config.options;
|
|
2728
|
-
const
|
|
3009
|
+
const baseUrl = (opts.baseUrl || opts.url || "http://localhost:8080").replace(/\/$/, "");
|
|
2729
3010
|
try {
|
|
2730
|
-
const response = await fetch(`${
|
|
2731
|
-
if (!response.ok) {
|
|
2732
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
2733
|
-
}
|
|
3011
|
+
const response = await fetch(`${baseUrl}/v1/.well-known/ready`);
|
|
3012
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
2734
3013
|
return {
|
|
2735
3014
|
healthy: true,
|
|
2736
3015
|
provider: "weaviate",
|
|
2737
|
-
capabilities: { endpoint:
|
|
3016
|
+
capabilities: { endpoint: baseUrl },
|
|
2738
3017
|
timestamp
|
|
2739
3018
|
};
|
|
2740
3019
|
} catch (error) {
|
|
@@ -2750,12 +3029,7 @@ var ProviderHealthCheck = class {
|
|
|
2750
3029
|
const opts = config.options;
|
|
2751
3030
|
const baseUrl = (opts.baseUrl || "").replace(/\/$/, "");
|
|
2752
3031
|
if (!baseUrl) {
|
|
2753
|
-
return {
|
|
2754
|
-
healthy: false,
|
|
2755
|
-
provider: "rest",
|
|
2756
|
-
error: "baseUrl is required",
|
|
2757
|
-
timestamp
|
|
2758
|
-
};
|
|
3032
|
+
return { healthy: false, provider: "rest", error: "baseUrl is required", timestamp };
|
|
2759
3033
|
}
|
|
2760
3034
|
try {
|
|
2761
3035
|
const response = await fetch(`${baseUrl}/health`, {
|
|
@@ -2818,11 +3092,7 @@ var ProviderHealthCheck = class {
|
|
|
2818
3092
|
return {
|
|
2819
3093
|
healthy: true,
|
|
2820
3094
|
provider: "openai",
|
|
2821
|
-
capabilities: {
|
|
2822
|
-
model: config.model,
|
|
2823
|
-
available: hasModel,
|
|
2824
|
-
totalModels: models.data.length
|
|
2825
|
-
},
|
|
3095
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.data.length },
|
|
2826
3096
|
timestamp
|
|
2827
3097
|
};
|
|
2828
3098
|
} catch (error) {
|
|
@@ -2843,12 +3113,7 @@ var ProviderHealthCheck = class {
|
|
|
2843
3113
|
max_tokens: 10,
|
|
2844
3114
|
messages: [{ role: "user", content: "ping" }]
|
|
2845
3115
|
});
|
|
2846
|
-
return {
|
|
2847
|
-
healthy: true,
|
|
2848
|
-
provider: "anthropic",
|
|
2849
|
-
capabilities: { model: config.model },
|
|
2850
|
-
timestamp
|
|
2851
|
-
};
|
|
3116
|
+
return { healthy: true, provider: "anthropic", capabilities: { model: config.model }, timestamp };
|
|
2852
3117
|
} catch (error) {
|
|
2853
3118
|
return {
|
|
2854
3119
|
healthy: false,
|
|
@@ -2862,20 +3127,14 @@ var ProviderHealthCheck = class {
|
|
|
2862
3127
|
const baseUrl = (config.baseUrl || "http://localhost:11434").replace(/\/$/, "");
|
|
2863
3128
|
try {
|
|
2864
3129
|
const response = await fetch(`${baseUrl}/api/tags`);
|
|
2865
|
-
if (!response.ok) {
|
|
2866
|
-
throw new Error(`Health check returned ${response.status}`);
|
|
2867
|
-
}
|
|
3130
|
+
if (!response.ok) throw new Error(`Health check returned ${response.status}`);
|
|
2868
3131
|
const data = await response.json();
|
|
2869
3132
|
const models = data.models || [];
|
|
2870
3133
|
const hasModel = models.some((m) => m.name === config.model);
|
|
2871
3134
|
return {
|
|
2872
3135
|
healthy: true,
|
|
2873
3136
|
provider: "ollama",
|
|
2874
|
-
capabilities: {
|
|
2875
|
-
model: config.model,
|
|
2876
|
-
available: hasModel,
|
|
2877
|
-
totalModels: models.length
|
|
2878
|
-
},
|
|
3137
|
+
capabilities: { model: config.model, available: hasModel, totalModels: models.length },
|
|
2879
3138
|
timestamp
|
|
2880
3139
|
};
|
|
2881
3140
|
} catch (error) {
|
|
@@ -2892,18 +3151,11 @@ var ProviderHealthCheck = class {
|
|
|
2892
3151
|
const baseUrlRaw = config.baseUrl || ((_a = config.options) == null ? void 0 : _a.baseUrl);
|
|
2893
3152
|
const baseUrl = (typeof baseUrlRaw === "string" ? baseUrlRaw : "").replace(/\/$/, "");
|
|
2894
3153
|
if (!baseUrl) {
|
|
2895
|
-
return {
|
|
2896
|
-
healthy: false,
|
|
2897
|
-
provider: config.provider,
|
|
2898
|
-
error: "baseUrl is required",
|
|
2899
|
-
timestamp
|
|
2900
|
-
};
|
|
3154
|
+
return { healthy: false, provider: config.provider, error: "baseUrl is required", timestamp };
|
|
2901
3155
|
}
|
|
2902
3156
|
try {
|
|
2903
3157
|
const headers = (_b = config.options) == null ? void 0 : _b.headers;
|
|
2904
|
-
const response = await fetch(`${baseUrl}/health`, {
|
|
2905
|
-
headers: headers || void 0
|
|
2906
|
-
});
|
|
3158
|
+
const response = await fetch(`${baseUrl}/health`, { headers: headers || void 0 });
|
|
2907
3159
|
return {
|
|
2908
3160
|
healthy: response.ok,
|
|
2909
3161
|
provider: config.provider,
|
|
@@ -2920,7 +3172,7 @@ var ProviderHealthCheck = class {
|
|
|
2920
3172
|
}
|
|
2921
3173
|
}
|
|
2922
3174
|
/**
|
|
2923
|
-
* Runs comprehensive health checks on all configured providers.
|
|
3175
|
+
* Runs comprehensive health checks on all configured providers in parallel.
|
|
2924
3176
|
*/
|
|
2925
3177
|
static async checkAll(vectorDbConfig, llmConfig, embeddingConfig) {
|
|
2926
3178
|
const [vectorDb, llm, embedding] = await Promise.all([
|