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