@retrivora-ai/rag-engine 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ChromaDBProvider-QNI7UCX4.mjs +8 -0
- package/dist/DocumentChunker-cfaMidtA.d.mts +93 -0
- package/dist/DocumentChunker-cfaMidtA.d.ts +93 -0
- package/dist/LLMFactory-JFOY2V4X.mjs +8 -0
- package/dist/MilvusProvider-OO6QGZDZ.mjs +8 -0
- package/dist/MongoDBProvider-WWVJG3WT.mjs +8 -0
- package/dist/PineconeProvider-NJ675H7U.mjs +8 -0
- package/dist/PostgreSQLProvider-ISNMD3BE.mjs +8 -0
- package/dist/QdrantProvider-LJWOIGES.mjs +8 -0
- package/dist/RagConfig-DG_0f8ka.d.mts +145 -0
- package/dist/RagConfig-DG_0f8ka.d.ts +145 -0
- package/dist/RedisProvider-ASONNYBI.mjs +8 -0
- package/dist/WeaviateProvider-PSDCUGC7.mjs +8 -0
- package/dist/chunk-6FODXNUF.mjs +91 -0
- package/dist/chunk-7NXI6ZWX.mjs +89 -0
- package/dist/chunk-AALIF3AL.mjs +91 -0
- package/dist/chunk-BP4U4TT5.mjs +548 -0
- package/dist/chunk-HUGLYKD6.mjs +84 -0
- package/dist/chunk-I4E63NIC.mjs +24 -0
- package/dist/chunk-JI6VD5TJ.mjs +387 -0
- package/dist/chunk-QEYVWVT5.mjs +102 -0
- package/dist/chunk-S5DRHETN.mjs +110 -0
- package/dist/{chunk-ZPXLQR5Q.mjs → chunk-UKDXCXW7.mjs} +5 -23
- package/dist/chunk-V75V7BT2.mjs +117 -0
- package/dist/chunk-VOIWNO5O.mjs +11 -0
- package/dist/chunk-VPNRDXIA.mjs +74 -0
- package/dist/handlers/index.d.mts +9 -33
- package/dist/handlers/index.d.ts +9 -33
- package/dist/handlers/index.js +1477 -962
- package/dist/handlers/index.mjs +4 -2
- package/dist/index.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +2 -2
- package/dist/index.mjs +4 -2
- package/dist/server.d.mts +220 -53
- package/dist/server.d.ts +220 -53
- package/dist/server.js +1531 -1099
- package/dist/server.mjs +55 -131
- package/package.json +19 -2
- package/src/app/page.tsx +1 -1
- package/src/components/MessageBubble.tsx +1 -1
- package/src/components/SourceCard.tsx +1 -1
- package/src/config/RagConfig.ts +1 -1
- package/src/config/serverConfig.ts +2 -2
- package/src/core/ConfigResolver.ts +69 -0
- package/src/core/Pipeline.ts +101 -0
- package/src/core/ProviderRegistry.ts +71 -0
- package/src/core/VectorPlugin.ts +52 -0
- package/src/handlers/index.ts +21 -100
- package/src/hooks/useRagChat.ts +1 -1
- package/src/index.ts +2 -6
- package/src/providers/vectordb/BaseVectorProvider.ts +61 -0
- package/src/providers/vectordb/ChromaDBProvider.ts +94 -0
- package/src/providers/vectordb/MilvusProvider.ts +100 -0
- package/src/providers/vectordb/MongoDBProvider.ts +118 -0
- package/src/{vectordb/adapters/PineconeAdapter.ts → providers/vectordb/PineconeProvider.ts} +21 -56
- package/src/{vectordb/adapters/PgVectorAdapter.ts → providers/vectordb/PostgreSQLProvider.ts} +23 -58
- package/src/providers/vectordb/QdrantProvider.ts +95 -0
- package/src/providers/vectordb/RedisProvider.ts +84 -0
- package/src/providers/vectordb/WeaviateProvider.ts +124 -0
- package/src/server.ts +16 -8
- package/src/test-refactor.ts +59 -0
- package/src/types/index.ts +24 -0
- package/src/utils/templateUtils.ts +6 -6
- package/dist/DocumentChunker-BUrIrcPk.d.mts +0 -43
- package/dist/DocumentChunker-BUrIrcPk.d.ts +0 -43
- package/dist/RAGPipeline-BmkIv1HD.d.mts +0 -298
- package/dist/RAGPipeline-BmkIv1HD.d.ts +0 -298
- package/dist/chunk-NVOMLHXW.mjs +0 -1259
- package/src/rag/RAGPipeline.ts +0 -200
- package/src/vectordb/IVectorDB.ts +0 -75
- package/src/vectordb/VectorDBFactory.ts +0 -41
- package/src/vectordb/adapters/MongoDbAdapter.ts +0 -175
- package/src/vectordb/adapters/UniversalVectorDBAdapter.ts +0 -177
package/dist/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,180 +1639,85 @@ 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;
|
|
1110
|
-
console.log(`[RAGPipeline] Searching Pinecone (Namespace: "${ns}", TopK: ${topK})...`);
|
|
1111
1651
|
const queryVector = await this.embeddingProvider.embed(question);
|
|
1112
1652
|
const rawMatches = await this.vectorDB.query(queryVector, topK, ns);
|
|
1113
|
-
console.log(`[RAGPipeline] Found ${rawMatches.length} raw matches in Pinecone.`);
|
|
1114
1653
|
const sources = rawMatches.filter((m) => m.score >= scoreThreshold);
|
|
1115
|
-
console.log(`[RAGPipeline] ${sources.length} sources remaining after threshold filter (min: ${scoreThreshold}).`);
|
|
1116
1654
|
const context = sources.length ? sources.map((m, i) => `[Source ${i + 1}]
|
|
1117
1655
|
${m.content}`).join("\n\n---\n\n") : "No relevant context found.";
|
|
1118
|
-
const messages = [
|
|
1119
|
-
...history,
|
|
1120
|
-
{ role: "user", content: question }
|
|
1121
|
-
];
|
|
1656
|
+
const messages = [...history, { role: "user", content: question }];
|
|
1122
1657
|
const reply = await this.llmProvider.chat(messages, context);
|
|
1123
1658
|
return { reply, sources };
|
|
1124
1659
|
}
|
|
1125
|
-
// ---------------------------------------------------------------------------
|
|
1126
|
-
// HEALTH
|
|
1127
|
-
// ---------------------------------------------------------------------------
|
|
1128
1660
|
async health() {
|
|
1661
|
+
await this.initialize();
|
|
1129
1662
|
const [vectorDB, llm] = await Promise.all([
|
|
1130
1663
|
this.vectorDB.ping().catch(() => false),
|
|
1131
1664
|
this.llmProvider.ping().catch(() => false)
|
|
1132
1665
|
]);
|
|
1133
1666
|
return { vectorDB, llm };
|
|
1134
1667
|
}
|
|
1135
|
-
// ---------------------------------------------------------------------------
|
|
1136
|
-
// DATA MANAGEMENT
|
|
1137
|
-
// ---------------------------------------------------------------------------
|
|
1138
|
-
async deleteDocument(docId, namespace) {
|
|
1139
|
-
await this.init();
|
|
1140
|
-
const ns = namespace != null ? namespace : this.config.projectId;
|
|
1141
|
-
await this.vectorDB.delete(docId, ns);
|
|
1142
|
-
}
|
|
1143
|
-
async deleteProject(namespace) {
|
|
1144
|
-
await this.init();
|
|
1145
|
-
const ns = namespace != null ? namespace : this.config.projectId;
|
|
1146
|
-
await this.vectorDB.deleteNamespace(ns);
|
|
1147
|
-
}
|
|
1148
1668
|
};
|
|
1149
1669
|
|
|
1150
|
-
// src/
|
|
1151
|
-
var
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
const value = env[name];
|
|
1161
|
-
if (!value) return fallback;
|
|
1162
|
-
const parsed = Number(value);
|
|
1163
|
-
if (!Number.isFinite(parsed)) {
|
|
1164
|
-
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);
|
|
1165
1680
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
if (allowed.includes(value)) {
|
|
1172
|
-
return value;
|
|
1681
|
+
/**
|
|
1682
|
+
* Get the current resolved configuration.
|
|
1683
|
+
*/
|
|
1684
|
+
getConfig() {
|
|
1685
|
+
return this.config;
|
|
1173
1686
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
1180
|
-
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
1181
|
-
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
1182
|
-
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
1183
|
-
const vectorDbOptions = {};
|
|
1184
|
-
if (vectorProvider === "pinecone") {
|
|
1185
|
-
vectorDbOptions.apiKey = (_c = readString(env, "PINECONE_API_KEY")) != null ? _c : "";
|
|
1186
|
-
vectorDbOptions.environment = (_d = readString(env, "PINECONE_ENVIRONMENT")) != null ? _d : "";
|
|
1187
|
-
} else if (vectorProvider === "pgvector") {
|
|
1188
|
-
vectorDbOptions.connectionString = (_e = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _e : "";
|
|
1189
|
-
vectorDbOptions.dimensions = embeddingDimensions;
|
|
1190
|
-
} else if (vectorProvider === "rest") {
|
|
1191
|
-
vectorDbOptions.baseUrl = (_f = readString(env, "VECTOR_DB_REST_URL")) != null ? _f : "";
|
|
1192
|
-
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { "api-key": readString(env, "VECTOR_DB_REST_API_KEY") } : {};
|
|
1193
|
-
} else if (vectorProvider === "universal_rest") {
|
|
1194
|
-
vectorDbOptions.baseUrl = (_h = (_g = readString(env, "VECTOR_BASE_URL")) != null ? _g : readString(env, "VECTOR_DB_REST_URL")) != null ? _h : "";
|
|
1195
|
-
vectorDbOptions.profile = readString(env, "VECTOR_UNIVERSAL_PROFILE");
|
|
1196
|
-
vectorDbOptions.headers = readString(env, "VECTOR_DB_REST_API_KEY") ? { Authorization: `Bearer ${readString(env, "VECTOR_DB_REST_API_KEY")}` } : {};
|
|
1197
|
-
} else if (vectorProvider === "mongodb") {
|
|
1198
|
-
vectorDbOptions.uri = (_i = readString(env, "MONGODB_URI")) != null ? _i : "";
|
|
1199
|
-
vectorDbOptions.database = (_j = readString(env, "MONGODB_DB")) != null ? _j : "";
|
|
1200
|
-
vectorDbOptions.collection = (_k = readString(env, "MONGODB_COLLECTION")) != null ? _k : "";
|
|
1201
|
-
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);
|
|
1202
1692
|
}
|
|
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
|
-
|
|
1231
|
-
}
|
|
1232
|
-
},
|
|
1233
|
-
embedding: {
|
|
1234
|
-
provider: embeddingProvider,
|
|
1235
|
-
model: (_q = readString(env, "EMBEDDING_MODEL")) != null ? _q : "text-embedding-3-small",
|
|
1236
|
-
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
1237
|
-
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
1238
|
-
dimensions: embeddingDimensions,
|
|
1239
|
-
options: {
|
|
1240
|
-
profile: readString(env, "EMBEDDING_UNIVERSAL_PROFILE")
|
|
1241
|
-
}
|
|
1242
|
-
},
|
|
1243
|
-
ui: {
|
|
1244
|
-
title: (_s = (_r = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _r : readString(env, "UI_TITLE")) != null ? _s : "AI Assistant",
|
|
1245
|
-
subtitle: (_u = (_t = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _t : readString(env, "UI_SUBTITLE")) != null ? _u : "Powered by RAG",
|
|
1246
|
-
primaryColor: (_w = (_v = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _v : readString(env, "UI_PRIMARY_COLOR")) != null ? _w : "#10b981",
|
|
1247
|
-
accentColor: (_y = (_x = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _x : readString(env, "UI_ACCENT_COLOR")) != null ? _y : "#3b82f6",
|
|
1248
|
-
logoUrl: (_z = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _z : readString(env, "UI_LOGO_URL"),
|
|
1249
|
-
placeholder: (_B = (_A = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _A : readString(env, "UI_PLACEHOLDER")) != null ? _B : "Ask me anything\u2026",
|
|
1250
|
-
showSources: ((_D = (_C = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _C : readString(env, "UI_SHOW_SOURCES")) != null ? _D : "true") !== "false",
|
|
1251
|
-
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.",
|
|
1252
|
-
visualStyle: (_H = (_G = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _G : readString(env, "UI_VISUAL_STYLE")) != null ? _H : "glass",
|
|
1253
|
-
borderRadius: (_J = (_I = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _I : readString(env, "UI_BORDER_RADIUS")) != null ? _J : "xl"
|
|
1254
|
-
},
|
|
1255
|
-
rag: {
|
|
1256
|
-
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
1257
|
-
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
1258
|
-
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
1259
|
-
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200)
|
|
1260
|
-
}
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
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();
|
|
1263
1721
|
|
|
1264
1722
|
// src/handlers/index.ts
|
|
1265
1723
|
var import_server = require("next/server");
|
|
@@ -1324,12 +1782,8 @@ var DocumentParser = class {
|
|
|
1324
1782
|
};
|
|
1325
1783
|
|
|
1326
1784
|
// src/handlers/index.ts
|
|
1327
|
-
function createChatHandler(config
|
|
1328
|
-
|
|
1329
|
-
function getPipeline() {
|
|
1330
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1331
|
-
return pipeline;
|
|
1332
|
-
}
|
|
1785
|
+
function createChatHandler(config) {
|
|
1786
|
+
const plugin = new VectorPlugin(config);
|
|
1333
1787
|
return async function POST(req) {
|
|
1334
1788
|
try {
|
|
1335
1789
|
const body = await req.json();
|
|
@@ -1337,8 +1791,7 @@ function createChatHandler(config, adapters) {
|
|
|
1337
1791
|
if (!(message == null ? void 0 : message.trim())) {
|
|
1338
1792
|
return import_server.NextResponse.json({ error: "message is required" }, { status: 400 });
|
|
1339
1793
|
}
|
|
1340
|
-
const
|
|
1341
|
-
const result = await rag.ask(message, history, namespace);
|
|
1794
|
+
const result = await plugin.chat(message, history, namespace);
|
|
1342
1795
|
return import_server.NextResponse.json(result);
|
|
1343
1796
|
} catch (err) {
|
|
1344
1797
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
@@ -1346,64 +1799,42 @@ function createChatHandler(config, adapters) {
|
|
|
1346
1799
|
}
|
|
1347
1800
|
};
|
|
1348
1801
|
}
|
|
1349
|
-
function createIngestHandler(config
|
|
1350
|
-
|
|
1351
|
-
function getPipeline() {
|
|
1352
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1353
|
-
return pipeline;
|
|
1354
|
-
}
|
|
1802
|
+
function createIngestHandler(config) {
|
|
1803
|
+
const plugin = new VectorPlugin(config);
|
|
1355
1804
|
return async function POST(req) {
|
|
1356
1805
|
try {
|
|
1357
1806
|
const body = await req.json();
|
|
1358
1807
|
const { documents, namespace } = body;
|
|
1359
1808
|
if (!Array.isArray(documents) || documents.length === 0) {
|
|
1360
|
-
return import_server.NextResponse.json(
|
|
1361
|
-
{ error: "documents array is required and must not be empty" },
|
|
1362
|
-
{ status: 400 }
|
|
1363
|
-
);
|
|
1809
|
+
return import_server.NextResponse.json({ error: "documents array is required" }, { status: 400 });
|
|
1364
1810
|
}
|
|
1365
|
-
const
|
|
1366
|
-
|
|
1367
|
-
const totalChunks = results.reduce((sum, r) => sum + r.chunksIngested, 0);
|
|
1368
|
-
return import_server.NextResponse.json({ results, totalChunks });
|
|
1811
|
+
const results = await plugin.ingest(documents, namespace);
|
|
1812
|
+
return import_server.NextResponse.json({ results });
|
|
1369
1813
|
} catch (err) {
|
|
1370
1814
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
1371
1815
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
1372
1816
|
}
|
|
1373
1817
|
};
|
|
1374
1818
|
}
|
|
1375
|
-
function createHealthHandler(config
|
|
1376
|
-
|
|
1377
|
-
function getPipeline() {
|
|
1378
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1379
|
-
return pipeline;
|
|
1380
|
-
}
|
|
1819
|
+
function createHealthHandler(config) {
|
|
1820
|
+
const plugin = new VectorPlugin(config);
|
|
1381
1821
|
return async function GET() {
|
|
1382
1822
|
try {
|
|
1383
|
-
const
|
|
1384
|
-
const health = await rag.health();
|
|
1823
|
+
const health = await plugin.health();
|
|
1385
1824
|
const status = health.vectorDB && health.llm ? "ok" : "degraded";
|
|
1386
1825
|
return import_server.NextResponse.json(__spreadProps(__spreadValues({
|
|
1387
1826
|
status
|
|
1388
1827
|
}, health), {
|
|
1389
|
-
project: config.projectId,
|
|
1390
1828
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1391
1829
|
}));
|
|
1392
1830
|
} catch (err) {
|
|
1393
1831
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
1394
|
-
return import_server.NextResponse.json(
|
|
1395
|
-
{ status: "error", error: message, timestamp: (/* @__PURE__ */ new Date()).toISOString() },
|
|
1396
|
-
{ status: 500 }
|
|
1397
|
-
);
|
|
1832
|
+
return import_server.NextResponse.json({ status: "error", error: message }, { status: 500 });
|
|
1398
1833
|
}
|
|
1399
1834
|
};
|
|
1400
1835
|
}
|
|
1401
|
-
function createUploadHandler(config
|
|
1402
|
-
|
|
1403
|
-
function getPipeline() {
|
|
1404
|
-
if (!pipeline) pipeline = new RAGPipeline(config, adapters);
|
|
1405
|
-
return pipeline;
|
|
1406
|
-
}
|
|
1836
|
+
function createUploadHandler(config) {
|
|
1837
|
+
const plugin = new VectorPlugin(config);
|
|
1407
1838
|
return async function POST(req) {
|
|
1408
1839
|
try {
|
|
1409
1840
|
const formData = await req.formData();
|
|
@@ -1427,15 +1858,8 @@ function createUploadHandler(config, adapters) {
|
|
|
1427
1858
|
};
|
|
1428
1859
|
})
|
|
1429
1860
|
);
|
|
1430
|
-
const
|
|
1431
|
-
|
|
1432
|
-
const totalChunks = results.reduce((sum, r) => sum + r.chunksIngested, 0);
|
|
1433
|
-
return import_server.NextResponse.json({
|
|
1434
|
-
message: "Upload successful",
|
|
1435
|
-
filesProcessed: files.length,
|
|
1436
|
-
totalChunks,
|
|
1437
|
-
results
|
|
1438
|
-
});
|
|
1861
|
+
const results = await plugin.ingest(documents, namespace);
|
|
1862
|
+
return import_server.NextResponse.json({ message: "Upload successful", results });
|
|
1439
1863
|
} catch (err) {
|
|
1440
1864
|
const message = err instanceof Error ? err.message : "Upload failed";
|
|
1441
1865
|
return import_server.NextResponse.json({ error: message }, { status: 500 });
|
|
@@ -1445,15 +1869,23 @@ function createUploadHandler(config, adapters) {
|
|
|
1445
1869
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1446
1870
|
0 && (module.exports = {
|
|
1447
1871
|
AnthropicProvider,
|
|
1872
|
+
BaseVectorProvider,
|
|
1873
|
+
ChromaDBProvider,
|
|
1874
|
+
ConfigResolver,
|
|
1448
1875
|
DocumentChunker,
|
|
1449
1876
|
LLMFactory,
|
|
1450
|
-
|
|
1877
|
+
MilvusProvider,
|
|
1878
|
+
MongoDBProvider,
|
|
1451
1879
|
OllamaProvider,
|
|
1452
1880
|
OpenAIProvider,
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1881
|
+
PineconeProvider,
|
|
1882
|
+
Pipeline,
|
|
1883
|
+
PostgreSQLProvider,
|
|
1884
|
+
ProviderRegistry,
|
|
1885
|
+
QdrantProvider,
|
|
1886
|
+
RedisProvider,
|
|
1887
|
+
VectorPlugin,
|
|
1888
|
+
WeaviateProvider,
|
|
1457
1889
|
createChatHandler,
|
|
1458
1890
|
createHealthHandler,
|
|
1459
1891
|
createIngestHandler,
|