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