@retrivora-ai/rag-engine 0.1.3 → 0.1.5
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 +8 -0
- package/dist/DocumentChunker-cfaMidtA.d.mts +93 -0
- package/dist/DocumentChunker-cfaMidtA.d.ts +93 -0
- package/dist/LLMFactory-JFOY2V4X.mjs +8 -0
- package/dist/MilvusProvider-OO6QGZDZ.mjs +8 -0
- package/dist/MongoDBProvider-WWVJG3WT.mjs +8 -0
- package/dist/PineconeProvider-NJ675H7U.mjs +8 -0
- package/dist/PostgreSQLProvider-ISNMD3BE.mjs +8 -0
- package/dist/QdrantProvider-LJWOIGES.mjs +8 -0
- package/dist/RagConfig-DG_0f8ka.d.mts +145 -0
- package/dist/RagConfig-DG_0f8ka.d.ts +145 -0
- package/dist/RedisProvider-ASONNYBI.mjs +8 -0
- package/dist/WeaviateProvider-PSDCUGC7.mjs +8 -0
- package/dist/chunk-6FODXNUF.mjs +91 -0
- package/dist/chunk-7NXI6ZWX.mjs +89 -0
- package/dist/chunk-AALIF3AL.mjs +91 -0
- package/dist/chunk-BP4U4TT5.mjs +548 -0
- package/dist/chunk-HUGLYKD6.mjs +84 -0
- package/dist/chunk-I4E63NIC.mjs +24 -0
- package/dist/chunk-JI6VD5TJ.mjs +387 -0
- package/dist/chunk-QEYVWVT5.mjs +102 -0
- package/dist/chunk-S5DRHETN.mjs +110 -0
- package/dist/{chunk-ZPXLQR5Q.mjs → chunk-UKDXCXW7.mjs} +5 -23
- package/dist/chunk-V75V7BT2.mjs +117 -0
- package/dist/chunk-VOIWNO5O.mjs +11 -0
- package/dist/chunk-VPNRDXIA.mjs +74 -0
- package/dist/handlers/index.d.mts +9 -33
- package/dist/handlers/index.d.ts +9 -33
- package/dist/handlers/index.js +1477 -962
- package/dist/handlers/index.mjs +4 -2
- package/dist/index.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -2
- package/dist/index.mjs +4 -2
- package/dist/server.d.mts +220 -53
- package/dist/server.d.ts +220 -53
- package/dist/server.js +1531 -1099
- package/dist/server.mjs +55 -131
- package/package.json +19 -2
- package/src/app/page.tsx +1 -1
- package/src/components/MessageBubble.tsx +1 -1
- package/src/components/SourceCard.tsx +1 -1
- package/src/config/RagConfig.ts +1 -1
- package/src/config/serverConfig.ts +2 -2
- package/src/core/ConfigResolver.ts +69 -0
- package/src/core/Pipeline.ts +101 -0
- package/src/core/ProviderRegistry.ts +71 -0
- package/src/core/VectorPlugin.ts +52 -0
- package/src/handlers/index.ts +21 -100
- package/src/hooks/useRagChat.ts +1 -1
- package/src/index.ts +2 -6
- package/src/providers/vectordb/BaseVectorProvider.ts +61 -0
- package/src/providers/vectordb/ChromaDBProvider.ts +94 -0
- package/src/providers/vectordb/MilvusProvider.ts +100 -0
- package/src/providers/vectordb/MongoDBProvider.ts +118 -0
- package/src/{vectordb/adapters/PineconeAdapter.ts → providers/vectordb/PineconeProvider.ts} +21 -56
- package/src/{vectordb/adapters/PgVectorAdapter.ts → providers/vectordb/PostgreSQLProvider.ts} +23 -58
- package/src/providers/vectordb/QdrantProvider.ts +95 -0
- package/src/providers/vectordb/RedisProvider.ts +84 -0
- package/src/providers/vectordb/WeaviateProvider.ts +124 -0
- package/src/server.ts +16 -8
- package/src/test-refactor.ts +59 -0
- package/src/types/index.ts +24 -0
- package/src/utils/templateUtils.ts +6 -6
- package/dist/DocumentChunker-BUrIrcPk.d.mts +0 -43
- package/dist/DocumentChunker-BUrIrcPk.d.ts +0 -43
- package/dist/RAGPipeline-BmkIv1HD.d.mts +0 -298
- package/dist/RAGPipeline-BmkIv1HD.d.ts +0 -298
- package/dist/chunk-NVOMLHXW.mjs +0 -1259
- package/src/rag/RAGPipeline.ts +0 -200
- package/src/vectordb/IVectorDB.ts +0 -75
- package/src/vectordb/VectorDBFactory.ts +0 -41
- package/src/vectordb/adapters/MongoDbAdapter.ts +0 -175
- package/src/vectordb/adapters/UniversalVectorDBAdapter.ts +0 -177
package/dist/handlers/index.js
CHANGED
|
@@ -22,6 +22,9 @@ var __spreadValues = (a, b) => {
|
|
|
22
22
|
return a;
|
|
23
23
|
};
|
|
24
24
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
25
|
+
var __esm = (fn, res) => function __init() {
|
|
26
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
27
|
+
};
|
|
25
28
|
var __export = (target, all) => {
|
|
26
29
|
for (var name in all)
|
|
27
30
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -44,227 +47,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
44
47
|
));
|
|
45
48
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
46
49
|
|
|
47
|
-
// src/handlers/index.ts
|
|
48
|
-
var handlers_exports = {};
|
|
49
|
-
__export(handlers_exports, {
|
|
50
|
-
createChatHandler: () => createChatHandler,
|
|
51
|
-
createHealthHandler: () => createHealthHandler,
|
|
52
|
-
createIngestHandler: () => createIngestHandler,
|
|
53
|
-
createUploadHandler: () => createUploadHandler
|
|
54
|
-
});
|
|
55
|
-
module.exports = __toCommonJS(handlers_exports);
|
|
56
|
-
var import_server = require("next/server");
|
|
57
|
-
|
|
58
|
-
// src/vectordb/adapters/PineconeAdapter.ts
|
|
59
|
-
var import_pinecone = require("@pinecone-database/pinecone");
|
|
60
|
-
var PineconeAdapter = class {
|
|
61
|
-
constructor(config) {
|
|
62
|
-
this.indexName = config.indexName;
|
|
63
|
-
const opts = config.options;
|
|
64
|
-
if (!opts.apiKey) throw new Error("[PineconeAdapter] options.apiKey is required");
|
|
65
|
-
this.apiKey = opts.apiKey;
|
|
66
|
-
}
|
|
67
|
-
async initialize() {
|
|
68
|
-
var _a, _b;
|
|
69
|
-
this.client = new import_pinecone.Pinecone({ apiKey: this.apiKey });
|
|
70
|
-
const indexes = await this.client.listIndexes();
|
|
71
|
-
const names = (_b = (_a = indexes.indexes) == null ? void 0 : _a.map((i) => i.name)) != null ? _b : [];
|
|
72
|
-
if (!names.includes(this.indexName)) {
|
|
73
|
-
throw new Error(
|
|
74
|
-
`[PineconeAdapter] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
index(namespace) {
|
|
79
|
-
const idx = this.client.index(this.indexName);
|
|
80
|
-
return namespace ? idx.namespace(namespace) : idx.namespace("");
|
|
81
|
-
}
|
|
82
|
-
async upsert(doc, namespace) {
|
|
83
|
-
var _a;
|
|
84
|
-
await this.index(namespace).upsert({
|
|
85
|
-
records: [
|
|
86
|
-
{
|
|
87
|
-
id: doc.id,
|
|
88
|
-
values: doc.vector,
|
|
89
|
-
metadata: __spreadValues({
|
|
90
|
-
content: doc.content
|
|
91
|
-
}, (_a = doc.metadata) != null ? _a : {})
|
|
92
|
-
}
|
|
93
|
-
]
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
async batchUpsert(docs, namespace) {
|
|
97
|
-
const BATCH = 100;
|
|
98
|
-
for (let i = 0; i < docs.length; i += BATCH) {
|
|
99
|
-
const records = docs.slice(i, i + BATCH).map((d) => {
|
|
100
|
-
var _a;
|
|
101
|
-
return {
|
|
102
|
-
id: d.id,
|
|
103
|
-
values: d.vector,
|
|
104
|
-
metadata: __spreadValues({
|
|
105
|
-
content: d.content
|
|
106
|
-
}, (_a = d.metadata) != null ? _a : {})
|
|
107
|
-
};
|
|
108
|
-
});
|
|
109
|
-
await this.index(namespace).upsert({ records });
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
async query(vector, topK, namespace, filter) {
|
|
113
|
-
var _a;
|
|
114
|
-
const result = await this.index(namespace).query(__spreadValues({
|
|
115
|
-
vector,
|
|
116
|
-
topK,
|
|
117
|
-
includeMetadata: true
|
|
118
|
-
}, filter ? { filter } : {}));
|
|
119
|
-
return ((_a = result.matches) != null ? _a : []).map((m) => {
|
|
120
|
-
var _a2;
|
|
121
|
-
const metadata = m.metadata;
|
|
122
|
-
const content = (metadata == null ? void 0 : metadata.content) || (metadata == null ? void 0 : metadata.text) || (metadata == null ? void 0 : metadata.body) || (metadata == null ? void 0 : metadata.description) || "";
|
|
123
|
-
return {
|
|
124
|
-
id: m.id,
|
|
125
|
-
score: (_a2 = m.score) != null ? _a2 : 0,
|
|
126
|
-
content,
|
|
127
|
-
metadata
|
|
128
|
-
};
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
async delete(id, namespace) {
|
|
132
|
-
await this.index(namespace).deleteOne({ id });
|
|
133
|
-
}
|
|
134
|
-
async deleteNamespace(namespace) {
|
|
135
|
-
await this.client.index(this.indexName).namespace(namespace).deleteAll();
|
|
136
|
-
}
|
|
137
|
-
async ping() {
|
|
138
|
-
try {
|
|
139
|
-
await this.client.listIndexes();
|
|
140
|
-
return true;
|
|
141
|
-
} catch (err) {
|
|
142
|
-
console.error("[PineconeAdapter] Ping failed:", err);
|
|
143
|
-
return false;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
async disconnect() {
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
// src/vectordb/adapters/PgVectorAdapter.ts
|
|
151
|
-
var import_pg = require("pg");
|
|
152
|
-
var PgVectorAdapter = class {
|
|
153
|
-
constructor(config) {
|
|
154
|
-
var _a;
|
|
155
|
-
this.tableName = config.indexName.replace(/[^a-z0-9_]/gi, "_");
|
|
156
|
-
const opts = config.options;
|
|
157
|
-
if (!opts.connectionString) {
|
|
158
|
-
throw new Error("[PgVectorAdapter] options.connectionString is required");
|
|
159
|
-
}
|
|
160
|
-
this.connectionString = opts.connectionString;
|
|
161
|
-
this.dimensions = (_a = opts.dimensions) != null ? _a : 1536;
|
|
162
|
-
}
|
|
163
|
-
async initialize() {
|
|
164
|
-
this.pool = new import_pg.Pool({ connectionString: this.connectionString });
|
|
165
|
-
const client = await this.pool.connect();
|
|
166
|
-
try {
|
|
167
|
-
await client.query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
168
|
-
await client.query(`
|
|
169
|
-
CREATE TABLE IF NOT EXISTS ${this.tableName} (
|
|
170
|
-
id TEXT PRIMARY KEY,
|
|
171
|
-
namespace TEXT NOT NULL DEFAULT '',
|
|
172
|
-
content TEXT NOT NULL,
|
|
173
|
-
metadata JSONB,
|
|
174
|
-
embedding VECTOR(${this.dimensions})
|
|
175
|
-
)
|
|
176
|
-
`);
|
|
177
|
-
await client.query(`
|
|
178
|
-
CREATE INDEX IF NOT EXISTS ${this.tableName}_embedding_idx
|
|
179
|
-
ON ${this.tableName}
|
|
180
|
-
USING hnsw (embedding vector_cosine_ops)
|
|
181
|
-
`);
|
|
182
|
-
} finally {
|
|
183
|
-
client.release();
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
async upsert(doc, namespace = "") {
|
|
187
|
-
var _a;
|
|
188
|
-
const vectorLiteral = `[${doc.vector.join(",")}]`;
|
|
189
|
-
await this.pool.query(
|
|
190
|
-
`INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
|
|
191
|
-
VALUES ($1, $2, $3, $4, $5::vector)
|
|
192
|
-
ON CONFLICT (id) DO UPDATE
|
|
193
|
-
SET namespace = EXCLUDED.namespace,
|
|
194
|
-
content = EXCLUDED.content,
|
|
195
|
-
metadata = EXCLUDED.metadata,
|
|
196
|
-
embedding = EXCLUDED.embedding`,
|
|
197
|
-
[doc.id, namespace, doc.content, JSON.stringify((_a = doc.metadata) != null ? _a : {}), vectorLiteral]
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
async batchUpsert(docs, namespace = "") {
|
|
201
|
-
for (const doc of docs) {
|
|
202
|
-
await this.upsert(doc, namespace);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
async query(vector, topK, namespace, filter) {
|
|
206
|
-
const vectorLiteral = `[${vector.join(",")}]`;
|
|
207
|
-
let whereClause = namespace ? `WHERE namespace = $3` : "";
|
|
208
|
-
const params = [vectorLiteral, topK];
|
|
209
|
-
if (namespace) params.push(namespace);
|
|
210
|
-
if (filter && Object.keys(filter).length > 0) {
|
|
211
|
-
const filterConditions = Object.entries(filter).map(([key, val]) => {
|
|
212
|
-
const paramIdx = params.length + 1;
|
|
213
|
-
params.push(JSON.stringify(val));
|
|
214
|
-
return `metadata->>'${key}' = $${paramIdx}`;
|
|
215
|
-
}).join(" AND ");
|
|
216
|
-
whereClause = whereClause ? `${whereClause} AND ${filterConditions}` : `WHERE ${filterConditions}`;
|
|
217
|
-
}
|
|
218
|
-
const result = await this.pool.query(
|
|
219
|
-
`SELECT id,
|
|
220
|
-
content,
|
|
221
|
-
metadata,
|
|
222
|
-
1 - (embedding <=> $1::vector) AS score
|
|
223
|
-
FROM ${this.tableName}
|
|
224
|
-
${whereClause}
|
|
225
|
-
ORDER BY embedding <=> $1::vector
|
|
226
|
-
LIMIT $2`,
|
|
227
|
-
params
|
|
228
|
-
);
|
|
229
|
-
return result.rows.map((row) => ({
|
|
230
|
-
id: String(row.id),
|
|
231
|
-
score: parseFloat(String(row.score)),
|
|
232
|
-
content: String(row.content),
|
|
233
|
-
metadata: row.metadata
|
|
234
|
-
}));
|
|
235
|
-
}
|
|
236
|
-
async delete(id, namespace) {
|
|
237
|
-
const where = namespace ? "WHERE id = $1 AND namespace = $2" : "WHERE id = $1";
|
|
238
|
-
const params = namespace ? [id, namespace] : [id];
|
|
239
|
-
await this.pool.query(`DELETE FROM ${this.tableName} ${where}`, params);
|
|
240
|
-
}
|
|
241
|
-
async deleteNamespace(namespace) {
|
|
242
|
-
await this.pool.query(
|
|
243
|
-
`DELETE FROM ${this.tableName} WHERE namespace = $1`,
|
|
244
|
-
[namespace]
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
async ping() {
|
|
248
|
-
try {
|
|
249
|
-
await this.pool.query("SELECT 1");
|
|
250
|
-
return true;
|
|
251
|
-
} catch (err) {
|
|
252
|
-
console.error("[PgVectorAdapter] Ping failed:", err);
|
|
253
|
-
return false;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
async disconnect() {
|
|
257
|
-
try {
|
|
258
|
-
await this.pool.end();
|
|
259
|
-
} catch (err) {
|
|
260
|
-
console.error("[PgVectorAdapter] Failed to disconnect:", err);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
// src/vectordb/adapters/UniversalVectorDBAdapter.ts
|
|
266
|
-
var import_axios = __toESM(require("axios"));
|
|
267
|
-
|
|
268
50
|
// src/utils/templateUtils.ts
|
|
269
51
|
function isRecord(value) {
|
|
270
52
|
return typeof value === "object" && value !== null;
|
|
@@ -292,676 +74,1394 @@ function buildPayload(template, vars) {
|
|
|
292
74
|
Raw payload: ${raw}`);
|
|
293
75
|
}
|
|
294
76
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
var LLM_PROFILES = {
|
|
305
|
-
"openai-compatible": OPENAI_BASE,
|
|
306
|
-
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
307
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
308
|
-
}),
|
|
309
|
-
"anthropic-claude": {
|
|
310
|
-
chatPath: "/v1/messages",
|
|
311
|
-
responseExtractPath: "content[0].text",
|
|
312
|
-
headers: { "anthropic-version": "2023-06-01" },
|
|
313
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
314
|
-
},
|
|
315
|
-
"google-gemini": {
|
|
316
|
-
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
317
|
-
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
318
|
-
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
319
|
-
},
|
|
320
|
-
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
321
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
322
|
-
}),
|
|
323
|
-
"ollama-standard": {
|
|
324
|
-
chatPath: "/api/chat",
|
|
325
|
-
embedPath: "/api/embeddings",
|
|
326
|
-
responseExtractPath: "message.content",
|
|
327
|
-
embedExtractPath: "embedding",
|
|
328
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
329
|
-
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
77
|
+
function mergeDefined(base, override) {
|
|
78
|
+
const merged = __spreadValues({}, base || {});
|
|
79
|
+
if (!override) {
|
|
80
|
+
return merged;
|
|
81
|
+
}
|
|
82
|
+
for (const [key, value] of Object.entries(override)) {
|
|
83
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
84
|
+
merged[key] = value;
|
|
85
|
+
}
|
|
330
86
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
responseExtractPath: "matches",
|
|
337
|
-
idPath: "id",
|
|
338
|
-
scorePath: "score",
|
|
339
|
-
contentPath: "metadata.content",
|
|
340
|
-
metadataPath: "metadata",
|
|
341
|
-
queryPayloadTemplate: '{"vector":{{vector}},"topK":{{topK}},"includeMetadata":true,"namespace":"{{namespace}}"}'
|
|
342
|
-
},
|
|
343
|
-
"mongodb-atlas": {
|
|
344
|
-
queryPath: "/action/aggregate",
|
|
345
|
-
responseExtractPath: "documents",
|
|
346
|
-
idPath: "_id",
|
|
347
|
-
scorePath: "score",
|
|
348
|
-
contentPath: "content",
|
|
349
|
-
metadataPath: "metadata",
|
|
350
|
-
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"}}}]}'
|
|
351
|
-
},
|
|
352
|
-
"chromadb": {
|
|
353
|
-
queryPath: "/api/v1/collections/{{index}}/query",
|
|
354
|
-
upsertPath: "/api/v1/collections/{{index}}/add",
|
|
355
|
-
responseExtractPath: "matches",
|
|
356
|
-
idPath: "id",
|
|
357
|
-
scorePath: "distance",
|
|
358
|
-
contentPath: "document",
|
|
359
|
-
metadataPath: "metadata"
|
|
360
|
-
},
|
|
361
|
-
"qdrant": {
|
|
362
|
-
queryPath: "/collections/{{index}}/points/search",
|
|
363
|
-
upsertPath: "/collections/{{index}}/points",
|
|
364
|
-
responseExtractPath: "result",
|
|
365
|
-
idPath: "id",
|
|
366
|
-
scorePath: "score",
|
|
367
|
-
contentPath: "payload.content",
|
|
368
|
-
metadataPath: "payload"
|
|
87
|
+
return merged;
|
|
88
|
+
}
|
|
89
|
+
var init_templateUtils = __esm({
|
|
90
|
+
"src/utils/templateUtils.ts"() {
|
|
91
|
+
"use strict";
|
|
369
92
|
}
|
|
370
|
-
};
|
|
93
|
+
});
|
|
371
94
|
|
|
372
|
-
// src/
|
|
373
|
-
var
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
this.opts = __spreadValues(__spreadValues({}, profile), (_b = config.options) != null ? _b : {});
|
|
385
|
-
if (!this.opts.baseUrl) {
|
|
386
|
-
throw new Error("[UniversalVectorDBAdapter] options.baseUrl is required");
|
|
387
|
-
}
|
|
388
|
-
this.http = import_axios.default.create({
|
|
389
|
-
baseURL: this.opts.baseUrl,
|
|
390
|
-
headers: __spreadValues({
|
|
391
|
-
"Content-Type": "application/json"
|
|
392
|
-
}, this.opts.headers || {}),
|
|
393
|
-
timeout: (_c = this.opts.timeout) != null ? _c : 3e4
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
async initialize() {
|
|
397
|
-
if (this.opts.pingPath) {
|
|
398
|
-
const ok = await this.ping();
|
|
399
|
-
if (!ok) {
|
|
400
|
-
throw new Error(`[UniversalVectorDBAdapter] Could not reach health endpoint: ${this.opts.pingPath}`);
|
|
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;
|
|
401
107
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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
|
+
};
|
|
437
159
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
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
|
+
};
|
|
469
227
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
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
|
+
};
|
|
474
296
|
}
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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
|
+
};
|
|
479
339
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
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
|
+
});
|
|
484
377
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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
|
+
};
|
|
490
454
|
}
|
|
491
|
-
|
|
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
|
+
};
|
|
492
508
|
}
|
|
493
|
-
};
|
|
509
|
+
});
|
|
494
510
|
|
|
495
|
-
// src/vectordb/
|
|
496
|
-
var
|
|
497
|
-
var
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
if (!this.uri || !this.dbName || !this.collectionName) {
|
|
507
|
-
throw new Error("MongoDbAdapter requires uri, database, and collection options.");
|
|
508
|
-
}
|
|
509
|
-
this.client = new import_mongodb.MongoClient(this.uri);
|
|
511
|
+
// src/providers/vectordb/BaseVectorProvider.ts
|
|
512
|
+
var BaseVectorProvider;
|
|
513
|
+
var init_BaseVectorProvider = __esm({
|
|
514
|
+
"src/providers/vectordb/BaseVectorProvider.ts"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
BaseVectorProvider = class {
|
|
517
|
+
constructor(config) {
|
|
518
|
+
this.config = config;
|
|
519
|
+
this.indexName = config.indexName || "default";
|
|
520
|
+
}
|
|
521
|
+
};
|
|
510
522
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// src/providers/vectordb/PineconeProvider.ts
|
|
526
|
+
var PineconeProvider_exports = {};
|
|
527
|
+
__export(PineconeProvider_exports, {
|
|
528
|
+
PineconeProvider: () => PineconeProvider
|
|
529
|
+
});
|
|
530
|
+
var import_pinecone, PineconeProvider;
|
|
531
|
+
var init_PineconeProvider = __esm({
|
|
532
|
+
"src/providers/vectordb/PineconeProvider.ts"() {
|
|
533
|
+
"use strict";
|
|
534
|
+
import_pinecone = require("@pinecone-database/pinecone");
|
|
535
|
+
init_BaseVectorProvider();
|
|
536
|
+
PineconeProvider = class extends BaseVectorProvider {
|
|
537
|
+
constructor(config) {
|
|
538
|
+
super(config);
|
|
539
|
+
const opts = config.options;
|
|
540
|
+
if (!opts.apiKey) throw new Error("[PineconeProvider] options.apiKey is required");
|
|
541
|
+
this.apiKey = opts.apiKey;
|
|
542
|
+
}
|
|
543
|
+
async initialize() {
|
|
544
|
+
var _a, _b;
|
|
545
|
+
this.client = new import_pinecone.Pinecone({ apiKey: this.apiKey });
|
|
546
|
+
const indexes = await this.client.listIndexes();
|
|
547
|
+
const names = (_b = (_a = indexes.indexes) == null ? void 0 : _a.map((i) => i.name)) != null ? _b : [];
|
|
548
|
+
if (!names.includes(this.indexName)) {
|
|
549
|
+
throw new Error(`[PineconeProvider] Index "${this.indexName}" not found.`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
index(namespace) {
|
|
553
|
+
const idx = this.client.index(this.indexName);
|
|
554
|
+
return namespace ? idx.namespace(namespace) : idx.namespace("");
|
|
555
|
+
}
|
|
556
|
+
async upsert(doc, namespace) {
|
|
557
|
+
var _a;
|
|
558
|
+
await this.index(namespace).upsert({
|
|
559
|
+
records: [{
|
|
560
|
+
id: doc.id,
|
|
561
|
+
values: doc.vector,
|
|
562
|
+
metadata: __spreadValues({ content: doc.content }, (_a = doc.metadata) != null ? _a : {})
|
|
563
|
+
}]
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
async batchUpsert(docs, namespace) {
|
|
567
|
+
const BATCH = 100;
|
|
568
|
+
for (let i = 0; i < docs.length; i += BATCH) {
|
|
569
|
+
const records = docs.slice(i, i + BATCH).map((d) => {
|
|
570
|
+
var _a;
|
|
571
|
+
return {
|
|
572
|
+
id: d.id,
|
|
573
|
+
values: d.vector,
|
|
574
|
+
metadata: __spreadValues({ content: d.content }, (_a = d.metadata) != null ? _a : {})
|
|
575
|
+
};
|
|
576
|
+
});
|
|
577
|
+
await this.index(namespace).upsert({ records });
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
async query(vector, topK, namespace, filter) {
|
|
581
|
+
var _a;
|
|
582
|
+
const result = await this.index(namespace).query(__spreadValues({
|
|
583
|
+
vector,
|
|
584
|
+
topK,
|
|
585
|
+
includeMetadata: true
|
|
586
|
+
}, filter ? { filter } : {}));
|
|
587
|
+
return ((_a = result.matches) != null ? _a : []).map((m) => {
|
|
588
|
+
var _a2, _b;
|
|
589
|
+
return {
|
|
590
|
+
id: m.id,
|
|
591
|
+
score: (_a2 = m.score) != null ? _a2 : 0,
|
|
592
|
+
content: ((_b = m.metadata) == null ? void 0 : _b.content) || "",
|
|
593
|
+
metadata: m.metadata
|
|
594
|
+
};
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
async delete(id, namespace) {
|
|
598
|
+
await this.index(namespace).deleteOne({ id });
|
|
599
|
+
}
|
|
600
|
+
async deleteNamespace(namespace) {
|
|
601
|
+
await this.client.index(this.indexName).namespace(namespace).deleteAll();
|
|
602
|
+
}
|
|
603
|
+
async ping() {
|
|
604
|
+
try {
|
|
605
|
+
await this.client.listIndexes();
|
|
606
|
+
return true;
|
|
607
|
+
} catch (e) {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
async disconnect() {
|
|
612
|
+
}
|
|
613
|
+
};
|
|
515
614
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
);
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
// src/providers/vectordb/PostgreSQLProvider.ts
|
|
618
|
+
var PostgreSQLProvider_exports = {};
|
|
619
|
+
__export(PostgreSQLProvider_exports, {
|
|
620
|
+
PostgreSQLProvider: () => PostgreSQLProvider
|
|
621
|
+
});
|
|
622
|
+
var import_pg, PostgreSQLProvider;
|
|
623
|
+
var init_PostgreSQLProvider = __esm({
|
|
624
|
+
"src/providers/vectordb/PostgreSQLProvider.ts"() {
|
|
625
|
+
"use strict";
|
|
626
|
+
import_pg = require("pg");
|
|
627
|
+
init_BaseVectorProvider();
|
|
628
|
+
PostgreSQLProvider = class extends BaseVectorProvider {
|
|
629
|
+
constructor(config) {
|
|
630
|
+
var _a;
|
|
631
|
+
super(config);
|
|
632
|
+
this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
|
|
633
|
+
const opts = config.options;
|
|
634
|
+
if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
|
|
635
|
+
this.connectionString = opts.connectionString;
|
|
636
|
+
this.dimensions = (_a = opts.dimensions) != null ? _a : 1536;
|
|
637
|
+
}
|
|
638
|
+
async initialize() {
|
|
639
|
+
this.pool = new import_pg.Pool({ connectionString: this.connectionString });
|
|
640
|
+
const client = await this.pool.connect();
|
|
641
|
+
try {
|
|
642
|
+
await client.query("CREATE EXTENSION IF NOT EXISTS vector");
|
|
643
|
+
await client.query(`
|
|
644
|
+
CREATE TABLE IF NOT EXISTS ${this.tableName} (
|
|
645
|
+
id TEXT PRIMARY KEY,
|
|
646
|
+
namespace TEXT NOT NULL DEFAULT '',
|
|
647
|
+
content TEXT NOT NULL,
|
|
648
|
+
metadata JSONB,
|
|
649
|
+
embedding VECTOR(${this.dimensions})
|
|
650
|
+
)
|
|
651
|
+
`);
|
|
652
|
+
await client.query(`
|
|
653
|
+
CREATE INDEX IF NOT EXISTS ${this.tableName}_embedding_idx
|
|
654
|
+
ON ${this.tableName}
|
|
655
|
+
USING hnsw (embedding vector_cosine_ops)
|
|
656
|
+
`);
|
|
657
|
+
} finally {
|
|
658
|
+
client.release();
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
async upsert(doc, namespace = "") {
|
|
662
|
+
var _a;
|
|
663
|
+
const vectorLiteral = `[${doc.vector.join(",")}]`;
|
|
664
|
+
await this.pool.query(
|
|
665
|
+
`INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
|
|
666
|
+
VALUES ($1, $2, $3, $4, $5::vector)
|
|
667
|
+
ON CONFLICT (id) DO UPDATE
|
|
668
|
+
SET namespace = EXCLUDED.namespace,
|
|
669
|
+
content = EXCLUDED.content,
|
|
670
|
+
metadata = EXCLUDED.metadata,
|
|
671
|
+
embedding = EXCLUDED.embedding`,
|
|
672
|
+
[doc.id, namespace, doc.content, JSON.stringify((_a = doc.metadata) != null ? _a : {}), vectorLiteral]
|
|
673
|
+
);
|
|
674
|
+
}
|
|
675
|
+
async batchUpsert(docs, namespace = "") {
|
|
676
|
+
for (const doc of docs) {
|
|
677
|
+
await this.upsert(doc, namespace);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
async query(vector, topK, namespace, filter) {
|
|
681
|
+
const vectorLiteral = `[${vector.join(",")}]`;
|
|
682
|
+
let whereClause = namespace ? `WHERE namespace = $3` : "";
|
|
683
|
+
const params = [vectorLiteral, topK];
|
|
684
|
+
if (namespace) params.push(namespace);
|
|
685
|
+
if (filter && Object.keys(filter).length > 0) {
|
|
686
|
+
const filterConditions = Object.entries(filter).map(([key, val]) => {
|
|
687
|
+
const paramIdx = params.length + 1;
|
|
688
|
+
params.push(JSON.stringify(val));
|
|
689
|
+
return `metadata->>'${key}' = $${paramIdx}`;
|
|
690
|
+
}).join(" AND ");
|
|
691
|
+
whereClause = whereClause ? `${whereClause} AND ${filterConditions}` : `WHERE ${filterConditions}`;
|
|
692
|
+
}
|
|
693
|
+
const result = await this.pool.query(
|
|
694
|
+
`SELECT id, content, metadata, 1 - (embedding <=> $1::vector) AS score
|
|
695
|
+
FROM ${this.tableName}
|
|
696
|
+
${whereClause}
|
|
697
|
+
ORDER BY embedding <=> $1::vector
|
|
698
|
+
LIMIT $2`,
|
|
699
|
+
params
|
|
700
|
+
);
|
|
701
|
+
return result.rows.map((row) => ({
|
|
702
|
+
id: String(row["id"]),
|
|
703
|
+
score: parseFloat(String(row["score"])),
|
|
704
|
+
content: String(row["content"]),
|
|
705
|
+
metadata: row["metadata"]
|
|
706
|
+
}));
|
|
707
|
+
}
|
|
708
|
+
async delete(id, namespace) {
|
|
709
|
+
const where = namespace ? "WHERE id = $1 AND namespace = $2" : "WHERE id = $1";
|
|
710
|
+
const params = namespace ? [id, namespace] : [id];
|
|
711
|
+
await this.pool.query(`DELETE FROM ${this.tableName} ${where}`, params);
|
|
712
|
+
}
|
|
713
|
+
async deleteNamespace(namespace) {
|
|
714
|
+
await this.pool.query(`DELETE FROM ${this.tableName} WHERE namespace = $1`, [namespace]);
|
|
715
|
+
}
|
|
716
|
+
async ping() {
|
|
717
|
+
try {
|
|
718
|
+
await this.pool.query("SELECT 1");
|
|
719
|
+
return true;
|
|
720
|
+
} catch (e) {
|
|
721
|
+
return false;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
async disconnect() {
|
|
725
|
+
await this.pool.end();
|
|
726
|
+
}
|
|
727
|
+
};
|
|
529
728
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
// src/providers/vectordb/MongoDBProvider.ts
|
|
732
|
+
var MongoDBProvider_exports = {};
|
|
733
|
+
__export(MongoDBProvider_exports, {
|
|
734
|
+
MongoDBProvider: () => MongoDBProvider
|
|
735
|
+
});
|
|
736
|
+
var import_mongodb, MongoDBProvider;
|
|
737
|
+
var init_MongoDBProvider = __esm({
|
|
738
|
+
"src/providers/vectordb/MongoDBProvider.ts"() {
|
|
739
|
+
"use strict";
|
|
740
|
+
import_mongodb = require("mongodb");
|
|
741
|
+
init_BaseVectorProvider();
|
|
742
|
+
MongoDBProvider = class extends BaseVectorProvider {
|
|
743
|
+
constructor(config) {
|
|
744
|
+
super(config);
|
|
745
|
+
const opts = config.options;
|
|
746
|
+
if (!opts.uri || !opts.database || !opts.collection) {
|
|
747
|
+
throw new Error("[MongoDBProvider] options uri, database, and collection are required.");
|
|
748
|
+
}
|
|
749
|
+
this.client = new import_mongodb.MongoClient(opts.uri);
|
|
750
|
+
this.dbName = opts.database;
|
|
751
|
+
this.collectionName = opts.collection;
|
|
752
|
+
this.embeddingKey = opts.embeddingKey || "embedding";
|
|
753
|
+
this.contentKey = opts.contentKey || "content";
|
|
754
|
+
this.metadataKey = opts.metadataKey || "metadata";
|
|
755
|
+
}
|
|
756
|
+
async initialize() {
|
|
757
|
+
await this.client.connect();
|
|
758
|
+
this.db = this.client.db(this.dbName);
|
|
759
|
+
this.collection = this.db.collection(this.collectionName);
|
|
760
|
+
}
|
|
761
|
+
async upsert(doc, namespace) {
|
|
762
|
+
const document = __spreadValues({
|
|
763
|
+
_id: doc.id,
|
|
764
|
+
[this.embeddingKey]: doc.vector,
|
|
765
|
+
[this.contentKey]: doc.content,
|
|
766
|
+
[this.metadataKey]: doc.metadata || {}
|
|
767
|
+
}, namespace ? { namespace } : {});
|
|
768
|
+
await this.collection.updateOne({ _id: doc.id }, { $set: document }, { upsert: true });
|
|
769
|
+
}
|
|
770
|
+
async batchUpsert(docs, namespace) {
|
|
771
|
+
const operations = docs.map((doc) => ({
|
|
772
|
+
updateOne: {
|
|
773
|
+
filter: { _id: doc.id },
|
|
774
|
+
update: {
|
|
775
|
+
$set: __spreadValues({
|
|
776
|
+
[this.embeddingKey]: doc.vector,
|
|
777
|
+
[this.contentKey]: doc.content,
|
|
778
|
+
[this.metadataKey]: doc.metadata || {}
|
|
779
|
+
}, namespace ? { namespace } : {})
|
|
780
|
+
},
|
|
781
|
+
upsert: true
|
|
782
|
+
}
|
|
783
|
+
}));
|
|
784
|
+
await this.collection.bulkWrite(operations);
|
|
785
|
+
}
|
|
786
|
+
async query(vector, topK, namespace, filter) {
|
|
787
|
+
const pipeline = [
|
|
788
|
+
{
|
|
789
|
+
$vectorSearch: __spreadValues({
|
|
790
|
+
index: this.config.options.indexName || "vector_index",
|
|
791
|
+
path: this.embeddingKey,
|
|
792
|
+
queryVector: vector,
|
|
793
|
+
numCandidates: Math.max(topK * 10, 100),
|
|
794
|
+
limit: topK
|
|
795
|
+
}, filter || namespace ? { filter: __spreadValues(__spreadValues({}, filter || {}), namespace ? { namespace } : {}) } : {})
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
$project: {
|
|
799
|
+
score: { $meta: "vectorSearchScore" },
|
|
800
|
+
content: `$${this.contentKey}`,
|
|
801
|
+
metadata: `$${this.metadataKey}`
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
];
|
|
805
|
+
const results = await this.collection.aggregate(pipeline).toArray();
|
|
806
|
+
return results.map((res) => ({
|
|
807
|
+
id: res["_id"].toString(),
|
|
808
|
+
score: res["score"],
|
|
809
|
+
content: res["content"],
|
|
810
|
+
metadata: res["metadata"]
|
|
811
|
+
}));
|
|
812
|
+
}
|
|
813
|
+
async delete(id, namespace) {
|
|
814
|
+
await this.collection.deleteOne(__spreadValues({ _id: id }, namespace ? { namespace } : {}));
|
|
815
|
+
}
|
|
816
|
+
async deleteNamespace(namespace) {
|
|
817
|
+
await this.collection.deleteMany({ namespace });
|
|
818
|
+
}
|
|
819
|
+
async ping() {
|
|
820
|
+
try {
|
|
821
|
+
await this.db.command({ ping: 1 });
|
|
822
|
+
return true;
|
|
823
|
+
} catch (e) {
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
async disconnect() {
|
|
828
|
+
await this.client.close();
|
|
829
|
+
}
|
|
830
|
+
};
|
|
547
831
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
{
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
// src/providers/vectordb/MilvusProvider.ts
|
|
835
|
+
var MilvusProvider_exports = {};
|
|
836
|
+
__export(MilvusProvider_exports, {
|
|
837
|
+
MilvusProvider: () => MilvusProvider
|
|
838
|
+
});
|
|
839
|
+
var import_axios3, MilvusProvider;
|
|
840
|
+
var init_MilvusProvider = __esm({
|
|
841
|
+
"src/providers/vectordb/MilvusProvider.ts"() {
|
|
842
|
+
"use strict";
|
|
843
|
+
import_axios3 = __toESM(require("axios"));
|
|
844
|
+
init_BaseVectorProvider();
|
|
845
|
+
MilvusProvider = class extends BaseVectorProvider {
|
|
846
|
+
constructor(config) {
|
|
847
|
+
super(config);
|
|
848
|
+
const opts = config.options;
|
|
849
|
+
const baseUrl = opts.baseUrl || opts.uri;
|
|
850
|
+
if (!baseUrl) throw new Error("[MilvusProvider] baseUrl/uri is required");
|
|
851
|
+
this.http = import_axios3.default.create({
|
|
852
|
+
baseURL: baseUrl,
|
|
853
|
+
headers: __spreadValues(__spreadValues({
|
|
854
|
+
"Content-Type": "application/json"
|
|
855
|
+
}, opts.headers || {}), opts.apiKey ? { Authorization: `Bearer ${opts.apiKey}` } : {})
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
async initialize() {
|
|
859
|
+
await this.ping();
|
|
860
|
+
}
|
|
861
|
+
async upsert(doc, namespace) {
|
|
862
|
+
const payload = {
|
|
863
|
+
collectionName: this.indexName,
|
|
864
|
+
data: [__spreadValues({
|
|
865
|
+
vector: doc.vector,
|
|
866
|
+
content: doc.content,
|
|
867
|
+
metadata: doc.metadata || {}
|
|
868
|
+
}, namespace ? { namespace } : {})]
|
|
869
|
+
};
|
|
870
|
+
await this.http.post("/v1/vector/upsert", payload);
|
|
871
|
+
}
|
|
872
|
+
async batchUpsert(docs, namespace) {
|
|
873
|
+
const payload = {
|
|
874
|
+
collectionName: this.indexName,
|
|
875
|
+
data: docs.map((doc) => __spreadValues({
|
|
876
|
+
vector: doc.vector,
|
|
877
|
+
content: doc.content,
|
|
878
|
+
metadata: doc.metadata || {}
|
|
879
|
+
}, namespace ? { namespace } : {}))
|
|
880
|
+
};
|
|
881
|
+
await this.http.post("/v1/vector/upsert", payload);
|
|
882
|
+
}
|
|
883
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
884
|
+
async query(vector, topK, namespace, _filter) {
|
|
885
|
+
const payload = {
|
|
886
|
+
collectionName: this.indexName,
|
|
887
|
+
vector,
|
|
888
|
+
limit: topK,
|
|
889
|
+
filter: namespace ? `namespace == "${namespace}"` : void 0,
|
|
890
|
+
outputFields: ["content", "metadata"]
|
|
891
|
+
};
|
|
892
|
+
const { data } = await this.http.post("/v1/vector/search", payload);
|
|
893
|
+
return (data.data || []).map((res) => ({
|
|
894
|
+
id: String(res["id"]),
|
|
895
|
+
score: res["distance"],
|
|
896
|
+
content: res["content"],
|
|
897
|
+
metadata: res["metadata"]
|
|
898
|
+
}));
|
|
899
|
+
}
|
|
900
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
901
|
+
async delete(id, _namespace) {
|
|
902
|
+
await this.http.post("/v1/vector/delete", {
|
|
903
|
+
collectionName: this.indexName,
|
|
904
|
+
id
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
908
|
+
async deleteNamespace(_namespace) {
|
|
909
|
+
}
|
|
910
|
+
async ping() {
|
|
911
|
+
try {
|
|
912
|
+
await this.http.get("/v1/health");
|
|
913
|
+
return true;
|
|
914
|
+
} catch (e) {
|
|
915
|
+
return false;
|
|
567
916
|
}
|
|
568
917
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
id: res._id.toString(),
|
|
573
|
-
score: res.score,
|
|
574
|
-
content: res.content,
|
|
575
|
-
metadata: res.metadata
|
|
576
|
-
}));
|
|
577
|
-
}
|
|
578
|
-
async delete(id, namespace) {
|
|
579
|
-
if (!this.collection) await this.initialize();
|
|
580
|
-
const query = __spreadValues({ _id: id }, namespace ? { namespace } : {});
|
|
581
|
-
await this.collection.deleteOne(query);
|
|
582
|
-
}
|
|
583
|
-
async deleteNamespace(namespace) {
|
|
584
|
-
if (!this.collection) await this.initialize();
|
|
585
|
-
await this.collection.deleteMany({ namespace });
|
|
586
|
-
}
|
|
587
|
-
async ping() {
|
|
588
|
-
try {
|
|
589
|
-
if (!this.collection) await this.initialize();
|
|
590
|
-
await this.db.command({ ping: 1 });
|
|
591
|
-
return true;
|
|
592
|
-
} catch (err) {
|
|
593
|
-
console.error("[MongoDbAdapter] Ping failed:", err);
|
|
594
|
-
return false;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
async disconnect() {
|
|
598
|
-
try {
|
|
599
|
-
await this.client.close();
|
|
600
|
-
this.db = void 0;
|
|
601
|
-
this.collection = void 0;
|
|
602
|
-
} catch (err) {
|
|
603
|
-
console.error("[MongoDbAdapter] Failed to disconnect:", err);
|
|
604
|
-
}
|
|
918
|
+
async disconnect() {
|
|
919
|
+
}
|
|
920
|
+
};
|
|
605
921
|
}
|
|
606
|
-
};
|
|
922
|
+
});
|
|
607
923
|
|
|
608
|
-
// src/vectordb/
|
|
609
|
-
var
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
if (
|
|
625
|
-
|
|
924
|
+
// src/providers/vectordb/QdrantProvider.ts
|
|
925
|
+
var QdrantProvider_exports = {};
|
|
926
|
+
__export(QdrantProvider_exports, {
|
|
927
|
+
QdrantProvider: () => QdrantProvider
|
|
928
|
+
});
|
|
929
|
+
var import_axios4, QdrantProvider;
|
|
930
|
+
var init_QdrantProvider = __esm({
|
|
931
|
+
"src/providers/vectordb/QdrantProvider.ts"() {
|
|
932
|
+
"use strict";
|
|
933
|
+
import_axios4 = __toESM(require("axios"));
|
|
934
|
+
init_BaseVectorProvider();
|
|
935
|
+
QdrantProvider = class extends BaseVectorProvider {
|
|
936
|
+
constructor(config) {
|
|
937
|
+
super(config);
|
|
938
|
+
const opts = config.options;
|
|
939
|
+
const baseUrl = opts.baseUrl;
|
|
940
|
+
if (!baseUrl) throw new Error("[QdrantProvider] baseUrl is required");
|
|
941
|
+
this.http = import_axios4.default.create({
|
|
942
|
+
baseURL: baseUrl,
|
|
943
|
+
headers: __spreadValues({
|
|
944
|
+
"Content-Type": "application/json"
|
|
945
|
+
}, opts.apiKey ? { "api-key": opts.apiKey } : {})
|
|
946
|
+
});
|
|
947
|
+
}
|
|
948
|
+
async initialize() {
|
|
949
|
+
await this.ping();
|
|
950
|
+
}
|
|
951
|
+
async upsert(doc, namespace) {
|
|
952
|
+
await this.batchUpsert([doc], namespace);
|
|
953
|
+
}
|
|
954
|
+
async batchUpsert(docs, namespace) {
|
|
955
|
+
const payload = {
|
|
956
|
+
points: docs.map((doc) => ({
|
|
957
|
+
id: doc.id,
|
|
958
|
+
vector: doc.vector,
|
|
959
|
+
payload: __spreadValues({
|
|
960
|
+
content: doc.content,
|
|
961
|
+
metadata: doc.metadata || {}
|
|
962
|
+
}, namespace ? { namespace } : {})
|
|
963
|
+
}))
|
|
964
|
+
};
|
|
965
|
+
await this.http.put(`/collections/${this.indexName}/points`, payload);
|
|
966
|
+
}
|
|
967
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
968
|
+
async query(vector, topK, namespace, _filter) {
|
|
969
|
+
const payload = {
|
|
970
|
+
vector,
|
|
971
|
+
limit: topK,
|
|
972
|
+
with_payload: true,
|
|
973
|
+
filter: namespace ? {
|
|
974
|
+
must: [{ key: "namespace", match: { value: namespace } }]
|
|
975
|
+
} : void 0
|
|
976
|
+
};
|
|
977
|
+
const { data } = await this.http.post(`/collections/${this.indexName}/points/search`, payload);
|
|
978
|
+
return (data.result || []).map((res) => {
|
|
979
|
+
var _a, _b;
|
|
980
|
+
return {
|
|
981
|
+
id: res["id"],
|
|
982
|
+
score: res["score"],
|
|
983
|
+
content: ((_a = res["payload"]) == null ? void 0 : _a.content) || "",
|
|
984
|
+
metadata: ((_b = res["payload"]) == null ? void 0 : _b.metadata) || {}
|
|
985
|
+
};
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
989
|
+
async delete(id, _namespace) {
|
|
990
|
+
await this.http.post(`/collections/${this.indexName}/points/delete`, {
|
|
991
|
+
points: [id]
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
995
|
+
async deleteNamespace(_namespace) {
|
|
996
|
+
await this.http.post(`/collections/${this.indexName}/points/delete`, {
|
|
997
|
+
filter: {
|
|
998
|
+
must: [{ key: "namespace", match: { value: _namespace } }]
|
|
999
|
+
}
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
async ping() {
|
|
1003
|
+
try {
|
|
1004
|
+
await this.http.get("/healthz");
|
|
1005
|
+
return true;
|
|
1006
|
+
} catch (e) {
|
|
1007
|
+
return false;
|
|
626
1008
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
}
|
|
1009
|
+
}
|
|
1010
|
+
async disconnect() {
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
631
1013
|
}
|
|
632
|
-
};
|
|
1014
|
+
});
|
|
633
1015
|
|
|
634
|
-
// src/
|
|
635
|
-
var
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
1016
|
+
// src/providers/vectordb/ChromaDBProvider.ts
|
|
1017
|
+
var ChromaDBProvider_exports = {};
|
|
1018
|
+
__export(ChromaDBProvider_exports, {
|
|
1019
|
+
ChromaDBProvider: () => ChromaDBProvider
|
|
1020
|
+
});
|
|
1021
|
+
var import_axios5, ChromaDBProvider;
|
|
1022
|
+
var init_ChromaDBProvider = __esm({
|
|
1023
|
+
"src/providers/vectordb/ChromaDBProvider.ts"() {
|
|
1024
|
+
"use strict";
|
|
1025
|
+
import_axios5 = __toESM(require("axios"));
|
|
1026
|
+
init_BaseVectorProvider();
|
|
1027
|
+
ChromaDBProvider = class extends BaseVectorProvider {
|
|
1028
|
+
constructor(config) {
|
|
1029
|
+
super(config);
|
|
1030
|
+
this.collectionId = "";
|
|
1031
|
+
const opts = config.options;
|
|
1032
|
+
const baseUrl = opts.baseUrl;
|
|
1033
|
+
if (!baseUrl) throw new Error("[ChromaDBProvider] baseUrl is required");
|
|
1034
|
+
this.http = import_axios5.default.create({
|
|
1035
|
+
baseURL: baseUrl,
|
|
1036
|
+
headers: { "Content-Type": "application/json" }
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
1039
|
+
async initialize() {
|
|
1040
|
+
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
1041
|
+
this.collectionId = data.id;
|
|
1042
|
+
}
|
|
1043
|
+
async upsert(doc, namespace) {
|
|
1044
|
+
await this.batchUpsert([doc], namespace);
|
|
1045
|
+
}
|
|
1046
|
+
async batchUpsert(docs, namespace) {
|
|
1047
|
+
const payload = {
|
|
1048
|
+
ids: docs.map((d) => d.id),
|
|
1049
|
+
embeddings: docs.map((d) => d.vector),
|
|
1050
|
+
documents: docs.map((d) => d.content),
|
|
1051
|
+
metadatas: docs.map((d) => __spreadValues(__spreadValues({}, d.metadata || {}), namespace ? { namespace } : {}))
|
|
1052
|
+
};
|
|
1053
|
+
await this.http.post(`/api/v1/collections/${this.collectionId}/add`, payload);
|
|
1054
|
+
}
|
|
1055
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1056
|
+
async query(vector, topK, namespace, _filter) {
|
|
1057
|
+
const payload = {
|
|
1058
|
+
query_embeddings: [vector],
|
|
1059
|
+
n_results: topK,
|
|
1060
|
+
where: namespace ? { namespace: { $eq: namespace } } : void 0
|
|
1061
|
+
};
|
|
1062
|
+
const { data } = await this.http.post(`/api/v1/collections/${this.collectionId}/query`, payload);
|
|
1063
|
+
const matches = [];
|
|
1064
|
+
if (data.ids && data.ids[0]) {
|
|
1065
|
+
for (let i = 0; i < data.ids[0].length; i++) {
|
|
1066
|
+
matches.push({
|
|
1067
|
+
id: data.ids[0][i],
|
|
1068
|
+
score: data.distances ? 1 - data.distances[0][i] : 0,
|
|
1069
|
+
content: data.documents ? data.documents[0][i] : "",
|
|
1070
|
+
metadata: data.metadatas ? data.metadatas[0][i] : {}
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
return matches;
|
|
1075
|
+
}
|
|
1076
|
+
async delete(id, _namespace) {
|
|
1077
|
+
await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
|
|
1078
|
+
ids: [id],
|
|
1079
|
+
where: _namespace ? { namespace: { $eq: _namespace } } : void 0
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
async deleteNamespace(_namespace) {
|
|
1083
|
+
await this.http.post(`/api/v1/collections/${this.collectionId}/delete`, {
|
|
1084
|
+
where: { namespace: { $eq: _namespace } }
|
|
1085
|
+
});
|
|
1086
|
+
}
|
|
1087
|
+
async ping() {
|
|
1088
|
+
try {
|
|
1089
|
+
await this.http.get("/api/v1/heartbeat");
|
|
1090
|
+
return true;
|
|
1091
|
+
} catch (e) {
|
|
1092
|
+
return false;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
async disconnect() {
|
|
1096
|
+
}
|
|
1097
|
+
};
|
|
642
1098
|
}
|
|
643
|
-
|
|
644
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
645
|
-
const systemContent = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Answer questions based on the provided context.
|
|
646
|
-
|
|
647
|
-
Context:
|
|
648
|
-
${context}`;
|
|
649
|
-
const systemMessage = {
|
|
650
|
-
role: "system",
|
|
651
|
-
content: systemContent.includes("{{context}}") ? systemContent.replace("{{context}}", context) : `${systemContent}
|
|
1099
|
+
});
|
|
652
1100
|
|
|
653
|
-
|
|
654
|
-
|
|
1101
|
+
// src/providers/vectordb/RedisProvider.ts
|
|
1102
|
+
var RedisProvider_exports = {};
|
|
1103
|
+
__export(RedisProvider_exports, {
|
|
1104
|
+
RedisProvider: () => RedisProvider
|
|
1105
|
+
});
|
|
1106
|
+
var import_axios6, RedisProvider;
|
|
1107
|
+
var init_RedisProvider = __esm({
|
|
1108
|
+
"src/providers/vectordb/RedisProvider.ts"() {
|
|
1109
|
+
"use strict";
|
|
1110
|
+
import_axios6 = __toESM(require("axios"));
|
|
1111
|
+
init_BaseVectorProvider();
|
|
1112
|
+
RedisProvider = class extends BaseVectorProvider {
|
|
1113
|
+
constructor(config) {
|
|
1114
|
+
super(config);
|
|
1115
|
+
const opts = config.options;
|
|
1116
|
+
const baseUrl = opts.baseUrl;
|
|
1117
|
+
if (!baseUrl) throw new Error("[RedisProvider] baseUrl is required");
|
|
1118
|
+
this.http = import_axios6.default.create({
|
|
1119
|
+
baseURL: baseUrl,
|
|
1120
|
+
headers: {
|
|
1121
|
+
"Content-Type": "application/json",
|
|
1122
|
+
Authorization: `Bearer ${opts.apiKey}`
|
|
1123
|
+
}
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
async initialize() {
|
|
1127
|
+
await this.ping();
|
|
1128
|
+
}
|
|
1129
|
+
async upsert(doc, namespace) {
|
|
1130
|
+
const key = namespace ? `${namespace}:${doc.id}` : doc.id;
|
|
1131
|
+
await this.http.post("/", ["JSON.SET", key, "$", JSON.stringify({
|
|
1132
|
+
vector: doc.vector,
|
|
1133
|
+
content: doc.content,
|
|
1134
|
+
metadata: doc.metadata || {}
|
|
1135
|
+
})]);
|
|
1136
|
+
}
|
|
1137
|
+
async batchUpsert(docs, namespace) {
|
|
1138
|
+
for (const doc of docs) {
|
|
1139
|
+
await this.upsert(doc, namespace);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1143
|
+
async query(vector, topK, namespace, _filter) {
|
|
1144
|
+
const payload = {
|
|
1145
|
+
index: this.indexName,
|
|
1146
|
+
vector,
|
|
1147
|
+
topK,
|
|
1148
|
+
namespace
|
|
1149
|
+
};
|
|
1150
|
+
const { data } = await this.http.post("/search", payload);
|
|
1151
|
+
return (data.results || []).map((res) => ({
|
|
1152
|
+
id: res["id"],
|
|
1153
|
+
score: res["score"],
|
|
1154
|
+
content: res["content"],
|
|
1155
|
+
metadata: res["metadata"]
|
|
1156
|
+
}));
|
|
1157
|
+
}
|
|
1158
|
+
async delete(id, namespace) {
|
|
1159
|
+
const key = namespace ? `${namespace}:${id}` : id;
|
|
1160
|
+
await this.http.post("/", ["DEL", key]);
|
|
1161
|
+
}
|
|
1162
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1163
|
+
async deleteNamespace(_namespace) {
|
|
1164
|
+
}
|
|
1165
|
+
async ping() {
|
|
1166
|
+
try {
|
|
1167
|
+
await this.http.post("/", ["PING"]);
|
|
1168
|
+
return true;
|
|
1169
|
+
} catch (e) {
|
|
1170
|
+
return false;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
async disconnect() {
|
|
1174
|
+
}
|
|
655
1175
|
};
|
|
656
|
-
const formattedMessages = [
|
|
657
|
-
systemMessage,
|
|
658
|
-
...messages.map((m) => ({
|
|
659
|
-
role: m.role,
|
|
660
|
-
content: m.content
|
|
661
|
-
}))
|
|
662
|
-
];
|
|
663
|
-
const completion = await this.client.chat.completions.create({
|
|
664
|
-
model: this.llmConfig.model,
|
|
665
|
-
messages: formattedMessages,
|
|
666
|
-
max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
|
|
667
|
-
temperature: (_e = (_d = options == null ? void 0 : options.temperature) != null ? _d : this.llmConfig.temperature) != null ? _e : 0.7,
|
|
668
|
-
stop: options == null ? void 0 : options.stop
|
|
669
|
-
});
|
|
670
|
-
return (_h = (_g = (_f = completion.choices[0]) == null ? void 0 : _f.message) == null ? void 0 : _g.content) != null ? _h : "";
|
|
671
|
-
}
|
|
672
|
-
async embed(text, options) {
|
|
673
|
-
const results = await this.batchEmbed([text], options);
|
|
674
|
-
return results[0];
|
|
675
|
-
}
|
|
676
|
-
async batchEmbed(texts, options) {
|
|
677
|
-
var _a, _b, _c, _d, _e;
|
|
678
|
-
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";
|
|
679
|
-
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
680
|
-
const client = apiKey !== this.llmConfig.apiKey ? new import_openai.default({ apiKey }) : this.client;
|
|
681
|
-
const response = await client.embeddings.create({ model, input: texts });
|
|
682
|
-
return response.data.map((d) => d.embedding);
|
|
683
1176
|
}
|
|
684
|
-
|
|
685
|
-
try {
|
|
686
|
-
await this.client.models.list();
|
|
687
|
-
return true;
|
|
688
|
-
} catch (err) {
|
|
689
|
-
console.error("[OpenAIProvider] Ping failed:", err);
|
|
690
|
-
return false;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
};
|
|
1177
|
+
});
|
|
694
1178
|
|
|
695
|
-
// src/
|
|
696
|
-
var
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
1179
|
+
// src/providers/vectordb/WeaviateProvider.ts
|
|
1180
|
+
var WeaviateProvider_exports = {};
|
|
1181
|
+
__export(WeaviateProvider_exports, {
|
|
1182
|
+
WeaviateProvider: () => WeaviateProvider
|
|
1183
|
+
});
|
|
1184
|
+
var import_axios7, WeaviateProvider;
|
|
1185
|
+
var init_WeaviateProvider = __esm({
|
|
1186
|
+
"src/providers/vectordb/WeaviateProvider.ts"() {
|
|
1187
|
+
"use strict";
|
|
1188
|
+
import_axios7 = __toESM(require("axios"));
|
|
1189
|
+
init_BaseVectorProvider();
|
|
1190
|
+
WeaviateProvider = class extends BaseVectorProvider {
|
|
1191
|
+
constructor(config) {
|
|
1192
|
+
super(config);
|
|
1193
|
+
const opts = config.options;
|
|
1194
|
+
const baseUrl = opts.baseUrl;
|
|
1195
|
+
if (!baseUrl) throw new Error("[WeaviateProvider] baseUrl is required");
|
|
1196
|
+
this.http = import_axios7.default.create({
|
|
1197
|
+
baseURL: baseUrl,
|
|
1198
|
+
headers: __spreadValues({
|
|
1199
|
+
"Content-Type": "application/json"
|
|
1200
|
+
}, opts.apiKey ? {
|
|
1201
|
+
"X-OpenAI-Api-Key": opts.apiKey,
|
|
1202
|
+
"Authorization": `Bearer ${opts.apiKey}`
|
|
1203
|
+
} : {})
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
async initialize() {
|
|
1207
|
+
await this.ping();
|
|
1208
|
+
}
|
|
1209
|
+
async upsert(doc, namespace) {
|
|
1210
|
+
const payload = {
|
|
1211
|
+
class: this.indexName,
|
|
1212
|
+
id: doc.id,
|
|
1213
|
+
vector: doc.vector,
|
|
1214
|
+
properties: {
|
|
1215
|
+
content: doc.content,
|
|
1216
|
+
metadata: JSON.stringify(doc.metadata || {}),
|
|
1217
|
+
namespace: namespace || ""
|
|
1218
|
+
}
|
|
1219
|
+
};
|
|
1220
|
+
await this.http.post("/v1/objects", payload);
|
|
1221
|
+
}
|
|
1222
|
+
async batchUpsert(docs, namespace) {
|
|
1223
|
+
const payload = {
|
|
1224
|
+
objects: docs.map((doc) => ({
|
|
1225
|
+
class: this.indexName,
|
|
1226
|
+
id: doc.id,
|
|
1227
|
+
vector: doc.vector,
|
|
1228
|
+
properties: {
|
|
1229
|
+
content: doc.content,
|
|
1230
|
+
metadata: JSON.stringify(doc.metadata || {}),
|
|
1231
|
+
namespace: namespace || ""
|
|
1232
|
+
}
|
|
1233
|
+
}))
|
|
1234
|
+
};
|
|
1235
|
+
await this.http.post("/v1/batch/objects", payload);
|
|
1236
|
+
}
|
|
1237
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1238
|
+
async query(vector, topK, namespace, _filter) {
|
|
1239
|
+
var _a, _b;
|
|
1240
|
+
const graphqlQuery = {
|
|
1241
|
+
query: `
|
|
1242
|
+
{
|
|
1243
|
+
Get {
|
|
1244
|
+
${this.indexName}(
|
|
1245
|
+
nearVector: {
|
|
1246
|
+
vector: ${JSON.stringify(vector)}
|
|
1247
|
+
}
|
|
1248
|
+
limit: ${topK}
|
|
1249
|
+
${namespace ? `where: { path: ["namespace"], operator: Equal, valueString: "${namespace}" }` : ""}
|
|
1250
|
+
) {
|
|
1251
|
+
content
|
|
1252
|
+
metadata
|
|
1253
|
+
_additional {
|
|
1254
|
+
id
|
|
1255
|
+
distance
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
`
|
|
1261
|
+
};
|
|
1262
|
+
const { data } = await this.http.post("/v1/graphql", graphqlQuery);
|
|
1263
|
+
const results = ((_b = (_a = data.data) == null ? void 0 : _a.Get) == null ? void 0 : _b[this.indexName]) || [];
|
|
1264
|
+
return results.map((res) => ({
|
|
1265
|
+
id: res["_additional"].id,
|
|
1266
|
+
score: 1 - res["_additional"].distance,
|
|
1267
|
+
content: res["content"],
|
|
1268
|
+
metadata: res["metadata"] ? JSON.parse(res["metadata"]) : {}
|
|
1269
|
+
}));
|
|
1270
|
+
}
|
|
1271
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1272
|
+
async delete(id, _namespace) {
|
|
1273
|
+
await this.http.delete(`/v1/objects/${this.indexName}/${id}`);
|
|
1274
|
+
}
|
|
1275
|
+
async deleteNamespace(namespace) {
|
|
1276
|
+
await this.http.post("/v1/batch/objects", {
|
|
1277
|
+
match: {
|
|
1278
|
+
class: this.indexName,
|
|
1279
|
+
where: { path: ["namespace"], operator: "Equal", valueString: namespace }
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
}
|
|
1283
|
+
async ping() {
|
|
1284
|
+
try {
|
|
1285
|
+
await this.http.get("/v1/.well-known/live");
|
|
1286
|
+
return true;
|
|
1287
|
+
} catch (e) {
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
async disconnect() {
|
|
1292
|
+
}
|
|
1293
|
+
};
|
|
703
1294
|
}
|
|
704
|
-
|
|
705
|
-
var _a, _b, _c;
|
|
706
|
-
const systemPrompt = (_a = this.llmConfig.systemPrompt) != null ? _a : `You are a helpful assistant. Use the context below to answer the user's question accurately.
|
|
1295
|
+
});
|
|
707
1296
|
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
1297
|
+
// src/handlers/index.ts
|
|
1298
|
+
var handlers_exports = {};
|
|
1299
|
+
__export(handlers_exports, {
|
|
1300
|
+
createChatHandler: () => createChatHandler,
|
|
1301
|
+
createHealthHandler: () => createHealthHandler,
|
|
1302
|
+
createIngestHandler: () => createIngestHandler,
|
|
1303
|
+
createUploadHandler: () => createUploadHandler
|
|
1304
|
+
});
|
|
1305
|
+
module.exports = __toCommonJS(handlers_exports);
|
|
1306
|
+
var import_server = require("next/server");
|
|
711
1307
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
const anthropicMessages = messages.map((m) => ({
|
|
715
|
-
role: m.role === "assistant" ? "assistant" : "user",
|
|
716
|
-
content: m.content
|
|
717
|
-
}));
|
|
718
|
-
const response = await this.client.messages.create({
|
|
719
|
-
model: this.llmConfig.model,
|
|
720
|
-
max_tokens: (_c = (_b = options == null ? void 0 : options.maxTokens) != null ? _b : this.llmConfig.maxTokens) != null ? _c : 1024,
|
|
721
|
-
system,
|
|
722
|
-
messages: anthropicMessages
|
|
723
|
-
});
|
|
724
|
-
const block = response.content[0];
|
|
725
|
-
return block.type === "text" ? block.text : "";
|
|
726
|
-
}
|
|
727
|
-
/**
|
|
728
|
-
* Anthropic does not offer an embedding API.
|
|
729
|
-
* This method throws with a clear error so developers know to configure
|
|
730
|
-
* a separate embedding provider (OpenAI or Ollama).
|
|
731
|
-
*/
|
|
732
|
-
async embed(text, options) {
|
|
733
|
-
void text;
|
|
734
|
-
void options;
|
|
735
|
-
throw new Error(
|
|
736
|
-
'[AnthropicProvider] Anthropic does not provide an embedding API. Set embedding.provider to "openai" or "ollama" in your RagConfig.'
|
|
737
|
-
);
|
|
738
|
-
}
|
|
739
|
-
async batchEmbed(texts, options) {
|
|
740
|
-
void texts;
|
|
741
|
-
void options;
|
|
742
|
-
throw new Error(
|
|
743
|
-
"[AnthropicProvider] Anthropic does not provide an embedding API."
|
|
744
|
-
);
|
|
745
|
-
}
|
|
746
|
-
async ping() {
|
|
747
|
-
try {
|
|
748
|
-
await this.client.models.list();
|
|
749
|
-
return true;
|
|
750
|
-
} catch (err) {
|
|
751
|
-
console.error("[AnthropicProvider] Ping failed:", err);
|
|
752
|
-
return false;
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
};
|
|
1308
|
+
// src/core/ConfigResolver.ts
|
|
1309
|
+
init_templateUtils();
|
|
756
1310
|
|
|
757
|
-
// src/
|
|
758
|
-
var
|
|
759
|
-
var
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
1311
|
+
// src/config/serverConfig.ts
|
|
1312
|
+
var VECTOR_DB_PROVIDERS = ["pinecone", "pgvector", "postgresql", "mongodb", "milvus", "qdrant", "chromadb", "redis", "weaviate", "rest", "universal_rest", "custom"];
|
|
1313
|
+
var LLM_PROVIDERS = ["openai", "anthropic", "ollama", "rest", "universal_rest", "custom"];
|
|
1314
|
+
var EMBEDDING_PROVIDERS = ["openai", "ollama", "rest", "universal_rest", "custom"];
|
|
1315
|
+
function readString(env, name) {
|
|
1316
|
+
var _a;
|
|
1317
|
+
const value = (_a = env[name]) == null ? void 0 : _a.trim();
|
|
1318
|
+
return value ? value : void 0;
|
|
1319
|
+
}
|
|
1320
|
+
function readNumber(env, name, fallback) {
|
|
1321
|
+
const value = env[name];
|
|
1322
|
+
if (!value) return fallback;
|
|
1323
|
+
const parsed = Number(value);
|
|
1324
|
+
if (!Number.isFinite(parsed)) {
|
|
1325
|
+
throw new Error(`[getRagConfig] ${name} must be a valid number`);
|
|
1326
|
+
}
|
|
1327
|
+
return parsed;
|
|
1328
|
+
}
|
|
1329
|
+
function readEnum(env, name, fallback, allowed) {
|
|
1330
|
+
var _a;
|
|
1331
|
+
const value = (_a = readString(env, name)) != null ? _a : fallback;
|
|
1332
|
+
if (allowed.includes(value)) {
|
|
1333
|
+
return value;
|
|
766
1334
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
1335
|
+
throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
|
|
1336
|
+
}
|
|
1337
|
+
function getRagConfig(env = process.env) {
|
|
1338
|
+
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;
|
|
1339
|
+
const projectId = (_b = (_a = readString(env, "RAG_PROJECT_ID")) != null ? _a : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : "__default__";
|
|
1340
|
+
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
1341
|
+
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
1342
|
+
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
1343
|
+
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
1344
|
+
const vectorDbOptions = {};
|
|
1345
|
+
if (vectorProvider === "pinecone") {
|
|
1346
|
+
vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
|
|
1347
|
+
vectorDbOptions.environment = (_d = readString(env, "PINECONE_ENVIRONMENT")) != null ? _d : "";
|
|
1348
|
+
} else if (vectorProvider === "pgvector") {
|
|
1349
|
+
vectorDbOptions.connectionString = (_e = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _e : "";
|
|
1350
|
+
vectorDbOptions.dimensions = embeddingDimensions;
|
|
1351
|
+
} else if (vectorProvider === "rest") {
|
|
1352
|
+
vectorDbOptions.baseUrl = (_f = readString(env, "VECTOR_DB_REST_URL")) != null ? _f : "";
|
|
1353
|
+
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { "api-key": readString(env, "VECTOR_DB_REST_API_KEY") } : {};
|
|
1354
|
+
} else if (vectorProvider === "universal_rest") {
|
|
1355
|
+
vectorDbOptions.baseUrl = (_h = (_g = readString(env, "VECTOR_BASE_URL")) != null ? _g : readString(env, "VECTOR_DB_REST_URL")) != null ? _h : "";
|
|
1356
|
+
vectorDbOptions.profile = readString(env, "VECTOR_UNIVERSAL_PROFILE");
|
|
1357
|
+
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { Authorization: `Bearer ${readString(env, "VECTOR_DB_REST_API_KEY")}` } : {};
|
|
1358
|
+
} else if (vectorProvider === "mongodb") {
|
|
1359
|
+
vectorDbOptions.uri = (_i = readString(env, "MONGODB_URI")) != null ? _i : "";
|
|
1360
|
+
vectorDbOptions.database = (_j = readString(env, "MONGODB_DB")) != null ? _j : "";
|
|
1361
|
+
vectorDbOptions.collection = (_k = readString(env, "MONGODB_COLLECTION")) != null ? _k : "";
|
|
1362
|
+
vectorDbOptions.indexName = (_l = readString(env, "MONGODB_INDEX_NAME")) != null ? _l : "vector_index";
|
|
1363
|
+
}
|
|
1364
|
+
const llmApiKeyByProvider = {
|
|
1365
|
+
openai: readString(env, "OPENAI_API_KEY"),
|
|
1366
|
+
anthropic: readString(env, "ANTHROPIC_API_KEY"),
|
|
1367
|
+
ollama: void 0,
|
|
1368
|
+
universal_rest: readString(env, "LLM_API_KEY")
|
|
1369
|
+
};
|
|
1370
|
+
const embeddingApiKeyByProvider = {
|
|
1371
|
+
openai: readString(env, "OPENAI_API_KEY"),
|
|
1372
|
+
ollama: void 0,
|
|
1373
|
+
custom: (_m = readString(env, "EMBEDDING_API_KEY")) != null ? _m : readString(env, "OPENAI_API_KEY")
|
|
1374
|
+
};
|
|
1375
|
+
return {
|
|
1376
|
+
projectId,
|
|
1377
|
+
vectorDb: {
|
|
1378
|
+
provider: vectorProvider,
|
|
1379
|
+
indexName: (_n = readString(env, "VECTOR_DB_INDEX")) != null ? _n : "rag-index",
|
|
1380
|
+
options: vectorDbOptions
|
|
1381
|
+
},
|
|
1382
|
+
llm: {
|
|
1383
|
+
provider: llmProvider,
|
|
1384
|
+
model: (_o = readString(env, "LLM_MODEL")) != null ? _o : "gpt-4o",
|
|
1385
|
+
apiKey: (_p = llmApiKeyByProvider[llmProvider]) != null ? _p : "",
|
|
1386
|
+
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
1387
|
+
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
1388
|
+
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 1024),
|
|
1389
|
+
temperature: readNumber(env, "LLM_TEMPERATURE", 0.7),
|
|
780
1390
|
options: {
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
]
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
await this.http.get("/api/tags");
|
|
812
|
-
return true;
|
|
813
|
-
} catch (err) {
|
|
814
|
-
console.error("[OllamaProvider] Ping failed:", err);
|
|
815
|
-
return false;
|
|
1391
|
+
profile: readString(env, "LLM_UNIVERSAL_PROFILE")
|
|
1392
|
+
}
|
|
1393
|
+
},
|
|
1394
|
+
embedding: {
|
|
1395
|
+
provider: embeddingProvider,
|
|
1396
|
+
model: (_q = readString(env, "EMBEDDING_MODEL")) != null ? _q : "text-embedding-3-small",
|
|
1397
|
+
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
1398
|
+
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
1399
|
+
dimensions: embeddingDimensions,
|
|
1400
|
+
options: {
|
|
1401
|
+
profile: readString(env, "EMBEDDING_UNIVERSAL_PROFILE")
|
|
1402
|
+
}
|
|
1403
|
+
},
|
|
1404
|
+
ui: {
|
|
1405
|
+
title: (_s = (_r = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _r : readString(env, "UI_TITLE")) != null ? _s : "AI Assistant",
|
|
1406
|
+
subtitle: (_u = (_t = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _t : readString(env, "UI_SUBTITLE")) != null ? _u : "Powered by RAG",
|
|
1407
|
+
primaryColor: (_w = (_v = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _v : readString(env, "UI_PRIMARY_COLOR")) != null ? _w : "#10b981",
|
|
1408
|
+
accentColor: (_y = (_x = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _x : readString(env, "UI_ACCENT_COLOR")) != null ? _y : "#3b82f6",
|
|
1409
|
+
logoUrl: (_z = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _z : readString(env, "UI_LOGO_URL"),
|
|
1410
|
+
placeholder: (_B = (_A = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _A : readString(env, "UI_PLACEHOLDER")) != null ? _B : "Ask me anything\u2026",
|
|
1411
|
+
showSources: ((_D = (_C = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _C : readString(env, "UI_SHOW_SOURCES")) != null ? _D : "true") !== "false",
|
|
1412
|
+
welcomeMessage: (_F = (_E = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _E : readString(env, "UI_WELCOME_MESSAGE")) != null ? _F : "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
1413
|
+
visualStyle: (_H = (_G = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _G : readString(env, "UI_VISUAL_STYLE")) != null ? _H : "glass",
|
|
1414
|
+
borderRadius: (_J = (_I = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _I : readString(env, "UI_BORDER_RADIUS")) != null ? _J : "xl"
|
|
1415
|
+
},
|
|
1416
|
+
rag: {
|
|
1417
|
+
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
1418
|
+
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
1419
|
+
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
1420
|
+
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200)
|
|
816
1421
|
}
|
|
817
|
-
}
|
|
818
|
-
}
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
819
1424
|
|
|
820
|
-
// src/
|
|
821
|
-
var
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
profile = LLM_PROFILES[options.profile] || {};
|
|
831
|
-
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
832
|
-
profile = options.profile;
|
|
833
|
-
}
|
|
834
|
-
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
835
|
-
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
836
|
-
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
837
|
-
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
838
|
-
const baseUrl = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl;
|
|
839
|
-
if (!baseUrl) {
|
|
840
|
-
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
1425
|
+
// src/core/ConfigResolver.ts
|
|
1426
|
+
var ConfigResolver = class {
|
|
1427
|
+
/**
|
|
1428
|
+
* Resolves the final configuration by merging host-provided config with defaults.
|
|
1429
|
+
* @param hostConfig - Partial configuration passed from the host application.
|
|
1430
|
+
*/
|
|
1431
|
+
static resolve(hostConfig) {
|
|
1432
|
+
const envConfig = getRagConfig();
|
|
1433
|
+
if (!hostConfig) {
|
|
1434
|
+
return envConfig;
|
|
841
1435
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
}
|
|
847
|
-
|
|
1436
|
+
return __spreadProps(__spreadValues(__spreadValues({}, envConfig), hostConfig), {
|
|
1437
|
+
projectId: hostConfig.projectId || envConfig.projectId,
|
|
1438
|
+
vectorDb: hostConfig.vectorDb ? __spreadProps(__spreadValues(__spreadValues({}, envConfig.vectorDb), hostConfig.vectorDb), {
|
|
1439
|
+
options: __spreadValues(__spreadValues({}, envConfig.vectorDb.options), hostConfig.vectorDb.options || {})
|
|
1440
|
+
}) : envConfig.vectorDb,
|
|
1441
|
+
llm: hostConfig.llm ? __spreadProps(__spreadValues(__spreadValues({}, envConfig.llm), hostConfig.llm), {
|
|
1442
|
+
options: __spreadValues(__spreadValues({}, envConfig.llm.options || {}), hostConfig.llm.options || {})
|
|
1443
|
+
}) : envConfig.llm,
|
|
1444
|
+
embedding: hostConfig.embedding ? __spreadProps(__spreadValues(__spreadValues({}, envConfig.embedding), hostConfig.embedding), {
|
|
1445
|
+
options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
|
|
1446
|
+
}) : envConfig.embedding,
|
|
1447
|
+
ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
|
|
1448
|
+
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
848
1449
|
});
|
|
849
1450
|
}
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
Context:
|
|
857
|
-
${context != null ? context : "None"}` },
|
|
858
|
-
...messages
|
|
859
|
-
];
|
|
860
|
-
let payload;
|
|
861
|
-
if (this.opts.chatPayloadTemplate) {
|
|
862
|
-
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
863
|
-
model: this.model,
|
|
864
|
-
messages: formattedMessages,
|
|
865
|
-
maxTokens: this.maxTokens,
|
|
866
|
-
temperature: this.temperature
|
|
867
|
-
});
|
|
868
|
-
} else {
|
|
869
|
-
payload = {
|
|
870
|
-
model: this.model,
|
|
871
|
-
messages: formattedMessages,
|
|
872
|
-
max_tokens: this.maxTokens,
|
|
873
|
-
temperature: this.temperature
|
|
874
|
-
};
|
|
875
|
-
}
|
|
876
|
-
const { data } = await this.http.post(path, payload);
|
|
877
|
-
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
878
|
-
const result = resolvePath(data, extractPath);
|
|
879
|
-
if (result === void 0) {
|
|
880
|
-
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
881
|
-
}
|
|
882
|
-
return String(result);
|
|
883
|
-
}
|
|
884
|
-
async embed(text) {
|
|
885
|
-
var _a, _b;
|
|
886
|
-
const path = (_a = this.opts.embedPath) != null ? _a : "/embeddings";
|
|
887
|
-
let payload;
|
|
888
|
-
if (this.opts.embedPayloadTemplate) {
|
|
889
|
-
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
890
|
-
model: this.model,
|
|
891
|
-
input: text
|
|
892
|
-
});
|
|
893
|
-
} else {
|
|
894
|
-
payload = {
|
|
895
|
-
model: this.model,
|
|
896
|
-
input: text
|
|
897
|
-
};
|
|
898
|
-
}
|
|
899
|
-
const { data } = await this.http.post(path, payload);
|
|
900
|
-
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
901
|
-
const vector = resolvePath(data, extractPath);
|
|
902
|
-
if (!Array.isArray(vector)) {
|
|
903
|
-
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
904
|
-
}
|
|
905
|
-
return vector;
|
|
906
|
-
}
|
|
907
|
-
async batchEmbed(texts) {
|
|
908
|
-
const vectors = [];
|
|
909
|
-
for (const text of texts) {
|
|
910
|
-
vectors.push(await this.embed(text));
|
|
1451
|
+
/**
|
|
1452
|
+
* Validates the configuration for required fields.
|
|
1453
|
+
*/
|
|
1454
|
+
static validate(config) {
|
|
1455
|
+
if (!config.projectId) {
|
|
1456
|
+
throw new Error("[ConfigResolver] projectId is required");
|
|
911
1457
|
}
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
async ping() {
|
|
915
|
-
try {
|
|
916
|
-
if (this.opts.pingPath) {
|
|
917
|
-
await this.http.get(this.opts.pingPath);
|
|
918
|
-
}
|
|
919
|
-
return true;
|
|
920
|
-
} catch (err) {
|
|
921
|
-
console.error("[UniversalLLMAdapter] Ping failed:", err);
|
|
922
|
-
return false;
|
|
1458
|
+
if (!config.vectorDb.provider) {
|
|
1459
|
+
throw new Error("[ConfigResolver] vectorDb.provider is required");
|
|
923
1460
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
// src/llm/LLMFactory.ts
|
|
928
|
-
var LLMFactory = class _LLMFactory {
|
|
929
|
-
static create(llmConfig, embeddingConfig) {
|
|
930
|
-
var _a;
|
|
931
|
-
switch (llmConfig.provider) {
|
|
932
|
-
case "openai":
|
|
933
|
-
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
934
|
-
case "anthropic":
|
|
935
|
-
return new AnthropicProvider(llmConfig, embeddingConfig);
|
|
936
|
-
case "ollama":
|
|
937
|
-
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
938
|
-
case "rest":
|
|
939
|
-
case "universal_rest":
|
|
940
|
-
case "custom":
|
|
941
|
-
return new UniversalLLMAdapter(llmConfig);
|
|
942
|
-
default:
|
|
943
|
-
if (llmConfig.baseUrl || ((_a = llmConfig.options) == null ? void 0 : _a.baseUrl)) {
|
|
944
|
-
return new UniversalLLMAdapter(llmConfig);
|
|
945
|
-
}
|
|
946
|
-
throw new Error(
|
|
947
|
-
`[LLMFactory] Unknown provider "${llmConfig.provider}". Supported: openai | anthropic | ollama | rest | custom`
|
|
948
|
-
);
|
|
1461
|
+
if (!config.llm.provider) {
|
|
1462
|
+
throw new Error("[ConfigResolver] llm.provider is required");
|
|
949
1463
|
}
|
|
950
1464
|
}
|
|
951
|
-
/**
|
|
952
|
-
* Creates a dedicated embedding-only provider.
|
|
953
|
-
* Useful when the LLM provider (e.g. Anthropic) doesn't support embeddings.
|
|
954
|
-
*/
|
|
955
|
-
static createEmbeddingProvider(embeddingConfig) {
|
|
956
|
-
const fakeLLMConfig = {
|
|
957
|
-
provider: embeddingConfig.provider,
|
|
958
|
-
model: embeddingConfig.model,
|
|
959
|
-
apiKey: embeddingConfig.apiKey,
|
|
960
|
-
baseUrl: embeddingConfig.baseUrl,
|
|
961
|
-
options: embeddingConfig.options
|
|
962
|
-
};
|
|
963
|
-
return _LLMFactory.create(fakeLLMConfig, embeddingConfig);
|
|
964
|
-
}
|
|
965
1465
|
};
|
|
966
1466
|
|
|
967
1467
|
// src/rag/DocumentChunker.ts
|
|
@@ -1023,42 +1523,88 @@ var DocumentChunker = class {
|
|
|
1023
1523
|
}
|
|
1024
1524
|
};
|
|
1025
1525
|
|
|
1026
|
-
// src/
|
|
1027
|
-
|
|
1028
|
-
|
|
1526
|
+
// src/core/ProviderRegistry.ts
|
|
1527
|
+
init_LLMFactory();
|
|
1528
|
+
var ProviderRegistry = class {
|
|
1529
|
+
/**
|
|
1530
|
+
* Register a custom vector provider.
|
|
1531
|
+
*/
|
|
1532
|
+
static registerVectorProvider(name, providerClass) {
|
|
1533
|
+
this.vectorProviders[name] = providerClass;
|
|
1534
|
+
}
|
|
1535
|
+
/**
|
|
1536
|
+
* Creates a vector database provider based on the configuration.
|
|
1537
|
+
*/
|
|
1538
|
+
static async createVectorProvider(config) {
|
|
1539
|
+
const { provider } = config;
|
|
1540
|
+
if (this.vectorProviders[provider]) {
|
|
1541
|
+
return new this.vectorProviders[provider](config);
|
|
1542
|
+
}
|
|
1543
|
+
switch (provider) {
|
|
1544
|
+
case "pinecone":
|
|
1545
|
+
const { PineconeProvider: PineconeProvider2 } = await Promise.resolve().then(() => (init_PineconeProvider(), PineconeProvider_exports));
|
|
1546
|
+
return new PineconeProvider2(config);
|
|
1547
|
+
case "pgvector":
|
|
1548
|
+
case "postgresql":
|
|
1549
|
+
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
1550
|
+
return new PostgreSQLProvider2(config);
|
|
1551
|
+
case "mongodb":
|
|
1552
|
+
const { MongoDBProvider: MongoDBProvider2 } = await Promise.resolve().then(() => (init_MongoDBProvider(), MongoDBProvider_exports));
|
|
1553
|
+
return new MongoDBProvider2(config);
|
|
1554
|
+
case "milvus":
|
|
1555
|
+
const { MilvusProvider: MilvusProvider2 } = await Promise.resolve().then(() => (init_MilvusProvider(), MilvusProvider_exports));
|
|
1556
|
+
return new MilvusProvider2(config);
|
|
1557
|
+
case "qdrant":
|
|
1558
|
+
const { QdrantProvider: QdrantProvider2 } = await Promise.resolve().then(() => (init_QdrantProvider(), QdrantProvider_exports));
|
|
1559
|
+
return new QdrantProvider2(config);
|
|
1560
|
+
case "chromadb":
|
|
1561
|
+
const { ChromaDBProvider: ChromaDBProvider2 } = await Promise.resolve().then(() => (init_ChromaDBProvider(), ChromaDBProvider_exports));
|
|
1562
|
+
return new ChromaDBProvider2(config);
|
|
1563
|
+
case "redis":
|
|
1564
|
+
const { RedisProvider: RedisProvider2 } = await Promise.resolve().then(() => (init_RedisProvider(), RedisProvider_exports));
|
|
1565
|
+
return new RedisProvider2(config);
|
|
1566
|
+
case "weaviate":
|
|
1567
|
+
const { WeaviateProvider: WeaviateProvider2 } = await Promise.resolve().then(() => (init_WeaviateProvider(), WeaviateProvider_exports));
|
|
1568
|
+
return new WeaviateProvider2(config);
|
|
1569
|
+
default:
|
|
1570
|
+
throw new Error(`[ProviderRegistry] Unsupported vector provider: ${provider}`);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Creates an LLM provider based on the configuration.
|
|
1575
|
+
*/
|
|
1576
|
+
static createLLMProvider(llmConfig, embeddingConfig) {
|
|
1577
|
+
return LLMFactory.create(llmConfig, embeddingConfig);
|
|
1578
|
+
}
|
|
1579
|
+
};
|
|
1580
|
+
ProviderRegistry.vectorProviders = {};
|
|
1581
|
+
|
|
1582
|
+
// src/core/Pipeline.ts
|
|
1583
|
+
var Pipeline = class {
|
|
1584
|
+
constructor(config) {
|
|
1029
1585
|
this.initialised = false;
|
|
1030
|
-
var _a, _b, _c, _d
|
|
1586
|
+
var _a, _b, _c, _d;
|
|
1031
1587
|
this.config = config;
|
|
1032
|
-
this.vectorDB = (_a = adapters == null ? void 0 : adapters.vectorDB) != null ? _a : VectorDBFactory.create(config.vectorDb);
|
|
1033
|
-
this.llmProvider = (_b = adapters == null ? void 0 : adapters.llmProvider) != null ? _b : LLMFactory.create(config.llm, config.embedding);
|
|
1034
|
-
if (adapters == null ? void 0 : adapters.embeddingProvider) {
|
|
1035
|
-
this.embeddingProvider = adapters.embeddingProvider;
|
|
1036
|
-
} else if (config.llm.provider === "anthropic") {
|
|
1037
|
-
this.embeddingProvider = LLMFactory.createEmbeddingProvider(config.embedding);
|
|
1038
|
-
} else {
|
|
1039
|
-
this.embeddingProvider = this.llmProvider;
|
|
1040
|
-
}
|
|
1041
1588
|
this.chunker = new DocumentChunker(
|
|
1042
|
-
(
|
|
1043
|
-
(
|
|
1589
|
+
(_b = (_a = config.rag) == null ? void 0 : _a.chunkSize) != null ? _b : 1e3,
|
|
1590
|
+
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
1044
1591
|
);
|
|
1045
1592
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1593
|
+
async initialize() {
|
|
1594
|
+
if (this.initialised) return;
|
|
1595
|
+
this.vectorDB = await ProviderRegistry.createVectorProvider(this.config.vectorDb);
|
|
1596
|
+
this.llmProvider = ProviderRegistry.createLLMProvider(this.config.llm, this.config.embedding);
|
|
1597
|
+
if (this.config.llm.provider === "anthropic") {
|
|
1598
|
+
const { LLMFactory: LLMFactory2 } = await Promise.resolve().then(() => (init_LLMFactory(), LLMFactory_exports));
|
|
1599
|
+
this.embeddingProvider = LLMFactory2.createEmbeddingProvider(this.config.embedding);
|
|
1600
|
+
} else {
|
|
1601
|
+
this.embeddingProvider = this.llmProvider;
|
|
1051
1602
|
}
|
|
1603
|
+
await this.vectorDB.initialize();
|
|
1604
|
+
this.initialised = true;
|
|
1052
1605
|
}
|
|
1053
|
-
// ---------------------------------------------------------------------------
|
|
1054
|
-
// INGEST
|
|
1055
|
-
// ---------------------------------------------------------------------------
|
|
1056
|
-
/**
|
|
1057
|
-
* Ingest one or more documents into the vector DB.
|
|
1058
|
-
* Automatically chunks, embeds, and upserts each chunk.
|
|
1059
|
-
*/
|
|
1060
1606
|
async ingest(documents, namespace) {
|
|
1061
|
-
await this.
|
|
1607
|
+
await this.initialize();
|
|
1062
1608
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
1063
1609
|
const results = [];
|
|
1064
1610
|
for (const doc of documents) {
|
|
@@ -1066,8 +1612,7 @@ var RAGPipeline = class {
|
|
|
1066
1612
|
docId: doc.docId,
|
|
1067
1613
|
metadata: doc.metadata
|
|
1068
1614
|
});
|
|
1069
|
-
const
|
|
1070
|
-
const vectors = await this.embeddingProvider.batchEmbed(chunkTexts);
|
|
1615
|
+
const vectors = await this.embeddingProvider.batchEmbed(chunks.map((c) => c.content));
|
|
1071
1616
|
const upsertDocs = chunks.map((chunk, i) => ({
|
|
1072
1617
|
id: chunk.id,
|
|
1073
1618
|
vector: vectors[i],
|
|
@@ -1076,64 +1621,68 @@ var RAGPipeline = class {
|
|
|
1076
1621
|
}));
|
|
1077
1622
|
await this.vectorDB.batchUpsert(upsertDocs, ns);
|
|
1078
1623
|
results.push({ docId: doc.docId, chunksIngested: chunks.length });
|
|
1079
|
-
console.log(`[RAGPipeline] Ingested ${chunks.length} chunks for doc: ${doc.docId}`);
|
|
1080
1624
|
}
|
|
1081
1625
|
return results;
|
|
1082
1626
|
}
|
|
1083
|
-
// ---------------------------------------------------------------------------
|
|
1084
|
-
// ASK
|
|
1085
|
-
// ---------------------------------------------------------------------------
|
|
1086
|
-
/**
|
|
1087
|
-
* Run a full RAG query:
|
|
1088
|
-
* 1. Embed the user question
|
|
1089
|
-
* 2. Retrieve top-K relevant chunks from the vector DB
|
|
1090
|
-
* 3. Filter by score threshold
|
|
1091
|
-
* 4. Build context string
|
|
1092
|
-
* 5. Call the LLM with chat history + context
|
|
1093
|
-
*/
|
|
1094
1627
|
async ask(question, history = [], namespace) {
|
|
1095
1628
|
var _a, _b, _c, _d;
|
|
1096
|
-
await this.
|
|
1629
|
+
await this.initialize();
|
|
1097
1630
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
1098
1631
|
const topK = (_b = (_a = this.config.rag) == null ? void 0 : _a.topK) != null ? _b : 5;
|
|
1099
1632
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0;
|
|
1100
|
-
console.log(`[RAGPipeline] Searching Pinecone (Namespace: "${ns}", TopK: ${topK})...`);
|
|
1101
1633
|
const queryVector = await this.embeddingProvider.embed(question);
|
|
1102
1634
|
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
1103
|
-
console.log(`[RAGPipeline] Found ${rawMatches.length} raw matches in Pinecone.`);
|
|
1104
1635
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
1105
|
-
console.log(`[RAGPipeline] ${sources.length} sources remaining after threshold filter (min: ${scoreThreshold}).`);
|
|
1106
1636
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
1107
1637
|
${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
1108
|
-
const messages = [
|
|
1109
|
-
...history,
|
|
1110
|
-
{ role: "user", content: question }
|
|
1111
|
-
];
|
|
1638
|
+
const messages = [...history, { role: "user", content: question }];
|
|
1112
1639
|
const reply = await this.llmProvider.chat(messages, context);
|
|
1113
1640
|
return { reply, sources };
|
|
1114
1641
|
}
|
|
1115
|
-
// ---------------------------------------------------------------------------
|
|
1116
|
-
// HEALTH
|
|
1117
|
-
// ---------------------------------------------------------------------------
|
|
1118
1642
|
async health() {
|
|
1643
|
+
await this.initialize();
|
|
1119
1644
|
const [vectorDB, llm] = await Promise.all([
|
|
1120
1645
|
this.vectorDB.ping().catch(() => false),
|
|
1121
1646
|
this.llmProvider.ping().catch(() => false)
|
|
1122
1647
|
]);
|
|
1123
1648
|
return { vectorDB, llm };
|
|
1124
1649
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1650
|
+
};
|
|
1651
|
+
|
|
1652
|
+
// src/core/VectorPlugin.ts
|
|
1653
|
+
var VectorPlugin = class {
|
|
1654
|
+
/**
|
|
1655
|
+
* Initializes the plugin with the host configuration.
|
|
1656
|
+
* @param hostConfig - Configuration object passed from the host application.
|
|
1657
|
+
*/
|
|
1658
|
+
constructor(hostConfig) {
|
|
1659
|
+
this.config = ConfigResolver.resolve(hostConfig);
|
|
1660
|
+
ConfigResolver.validate(this.config);
|
|
1661
|
+
this.pipeline = new Pipeline(this.config);
|
|
1132
1662
|
}
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1663
|
+
/**
|
|
1664
|
+
* Get the current resolved configuration.
|
|
1665
|
+
*/
|
|
1666
|
+
getConfig() {
|
|
1667
|
+
return this.config;
|
|
1668
|
+
}
|
|
1669
|
+
/**
|
|
1670
|
+
* Run a chat query.
|
|
1671
|
+
*/
|
|
1672
|
+
async chat(message, history = [], namespace) {
|
|
1673
|
+
return this.pipeline.ask(message, history, namespace);
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Ingest documents into the vector database.
|
|
1677
|
+
*/
|
|
1678
|
+
async ingest(documents, namespace) {
|
|
1679
|
+
return this.pipeline.ingest(documents, namespace);
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Check the health of the connected providers.
|
|
1683
|
+
*/
|
|
1684
|
+
async health() {
|
|
1685
|
+
return this.pipeline.health();
|
|
1137
1686
|
}
|
|
1138
1687
|
};
|
|
1139
1688
|
|
|
@@ -1197,12 +1746,8 @@ var DocumentParser = class {
|
|
|
1197
1746
|
};
|
|
1198
1747
|
|
|
1199
1748
|
// src/handlers/index.ts
|
|
1200
|
-
function createChatHandler(config
|
|
1201
|
-
|
|
1202
|
-
function getPipeline() {
|
|
1203
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1204
|
-
return pipeline;
|
|
1205
|
-
}
|
|
1749
|
+
function createChatHandler(config) {
|
|
1750
|
+
const plugin = new VectorPlugin(config);
|
|
1206
1751
|
return async function POST(req) {
|
|
1207
1752
|
try {
|
|
1208
1753
|
const body = await req.json();
|
|
@@ -1210,8 +1755,7 @@ function createChatHandler(config, adapters) {
|
|
|
1210
1755
|
if (!(message == null ? void 0 : message.trim())) {
|
|
1211
1756
|
return import_server.NextResponse.json({ error: "message is required" }, { status: 400 });
|
|
1212
1757
|
}
|
|
1213
|
-
const
|
|
1214
|
-
const result = await rag.ask(message, history, namespace);
|
|
1758
|
+
const result = await plugin.chat(message, history, namespace);
|
|
1215
1759
|
return import_server.NextResponse.json(result);
|
|
1216
1760
|
} catch (err) {
|
|
1217
1761
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
@@ -1219,64 +1763,42 @@ function createChatHandler(config, adapters) {
|
|
|
1219
1763
|
}
|
|
1220
1764
|
};
|
|
1221
1765
|
}
|
|
1222
|
-
function createIngestHandler(config
|
|
1223
|
-
|
|
1224
|
-
function getPipeline() {
|
|
1225
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1226
|
-
return pipeline;
|
|
1227
|
-
}
|
|
1766
|
+
function createIngestHandler(config) {
|
|
1767
|
+
const plugin = new VectorPlugin(config);
|
|
1228
1768
|
return async function POST(req) {
|
|
1229
1769
|
try {
|
|
1230
1770
|
const body = await req.json();
|
|
1231
1771
|
const { documents, namespace } = body;
|
|
1232
1772
|
if (!Array.isArray(documents) || documents.length === 0) {
|
|
1233
|
-
return import_server.NextResponse.json(
|
|
1234
|
-
{ error: "documents array is required and must not be empty" },
|
|
1235
|
-
{ status: 400 }
|
|
1236
|
-
);
|
|
1773
|
+
return import_server.NextResponse.json({ error: "documents array is required" }, { status: 400 });
|
|
1237
1774
|
}
|
|
1238
|
-
const
|
|
1239
|
-
|
|
1240
|
-
const totalChunks = results.reduce((sum, r) => sum + r.chunksIngested, 0);
|
|
1241
|
-
return import_server.NextResponse.json({ results, totalChunks });
|
|
1775
|
+
const results = await plugin.ingest(documents, namespace);
|
|
1776
|
+
return import_server.NextResponse.json({ results });
|
|
1242
1777
|
} catch (err) {
|
|
1243
1778
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
1244
1779
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
1245
1780
|
}
|
|
1246
1781
|
};
|
|
1247
1782
|
}
|
|
1248
|
-
function createHealthHandler(config
|
|
1249
|
-
|
|
1250
|
-
function getPipeline() {
|
|
1251
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1252
|
-
return pipeline;
|
|
1253
|
-
}
|
|
1783
|
+
function createHealthHandler(config) {
|
|
1784
|
+
const plugin = new VectorPlugin(config);
|
|
1254
1785
|
return async function GET() {
|
|
1255
1786
|
try {
|
|
1256
|
-
const
|
|
1257
|
-
const health = await rag.health();
|
|
1787
|
+
const health = await plugin.health();
|
|
1258
1788
|
const status = health.vectorDB && health.llm ? "ok" : "degraded";
|
|
1259
1789
|
return import_server.NextResponse.json(__spreadProps(__spreadValues({
|
|
1260
1790
|
status
|
|
1261
1791
|
}, health), {
|
|
1262
|
-
project: config.projectId,
|
|
1263
1792
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1264
1793
|
}));
|
|
1265
1794
|
} catch (err) {
|
|
1266
1795
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1267
|
-
return import_server.NextResponse.json(
|
|
1268
|
-
{ status: "error", error: message, timestamp: (/* @__PURE__ */ new Date()).toISOString() },
|
|
1269
|
-
{ status: 500 }
|
|
1270
|
-
);
|
|
1796
|
+
return import_server.NextResponse.json({ status: "error", error: message }, { status: 500 });
|
|
1271
1797
|
}
|
|
1272
1798
|
};
|
|
1273
1799
|
}
|
|
1274
|
-
function createUploadHandler(config
|
|
1275
|
-
|
|
1276
|
-
function getPipeline() {
|
|
1277
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1278
|
-
return pipeline;
|
|
1279
|
-
}
|
|
1800
|
+
function createUploadHandler(config) {
|
|
1801
|
+
const plugin = new VectorPlugin(config);
|
|
1280
1802
|
return async function POST(req) {
|
|
1281
1803
|
try {
|
|
1282
1804
|
const formData = await req.formData();
|
|
@@ -1300,15 +1822,8 @@ function createUploadHandler(config, adapters) {
|
|
|
1300
1822
|
};
|
|
1301
1823
|
})
|
|
1302
1824
|
);
|
|
1303
|
-
const
|
|
1304
|
-
|
|
1305
|
-
const totalChunks = results.reduce((sum, r) => sum + r.chunksIngested, 0);
|
|
1306
|
-
return import_server.NextResponse.json({
|
|
1307
|
-
message: "Upload successful",
|
|
1308
|
-
filesProcessed: files.length,
|
|
1309
|
-
totalChunks,
|
|
1310
|
-
results
|
|
1311
|
-
});
|
|
1825
|
+
const results = await plugin.ingest(documents, namespace);
|
|
1826
|
+
return import_server.NextResponse.json({ message: "Upload successful", results });
|
|
1312
1827
|
} catch (err) {
|
|
1313
1828
|
const message = err instanceof Error ? err.message : "Upload failed";
|
|
1314
1829
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|