@retrivora-ai/rag-engine 1.9.7 → 1.9.8
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/README.md +127 -135
- package/dist/{ILLMProvider-Bhk6zJOK.d.mts → ILLMProvider-B8ROITYK.d.mts} +57 -2
- package/dist/{ILLMProvider-Bhk6zJOK.d.ts → ILLMProvider-B8ROITYK.d.ts} +57 -2
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +2198 -457
- package/dist/handlers/index.mjs +2195 -457
- package/dist/{index-BJ4cd-t5.d.mts → index-B8PbEFSY.d.mts} +12 -2
- package/dist/{index-Bu7T6xgr.d.ts → index-BCPKUAVL.d.ts} +27 -52
- package/dist/{index-C3SVtPYg.d.mts → index-CrxCy36A.d.mts} +27 -52
- package/dist/{index-B9J_XEh0.d.ts → index-DNvoi-sV.d.ts} +12 -2
- package/dist/index.css +578 -273
- package/dist/index.d.mts +29 -7
- package/dist/index.d.ts +29 -7
- package/dist/index.js +1160 -282
- package/dist/index.mjs +1185 -292
- package/dist/server.d.mts +62 -6
- package/dist/server.d.ts +62 -6
- package/dist/server.js +2061 -306
- package/dist/server.mjs +2055 -306
- package/package.json +11 -7
- package/src/app/constants.tsx +37 -7
- package/src/components/AmbientBackground.tsx +10 -10
- package/src/components/ArchitectureCard.tsx +43 -7
- package/src/components/ArchitectureCardsSection.tsx +37 -4
- package/src/components/ChatWidget.tsx +2 -1
- package/src/components/ChatWindow.tsx +4 -1
- package/src/components/CodeViewer.tsx +19 -14
- package/src/components/DocViewer.tsx +43 -49
- package/src/components/Documentation.tsx +71 -51
- package/src/components/Hero.tsx +103 -20
- package/src/components/Lifecycle.tsx +65 -25
- package/src/components/MarkdownComponents.tsx +44 -1
- package/src/components/MessageBubble.tsx +162 -50
- package/src/components/constants.tsx +4 -0
- package/src/config/RagConfig.ts +46 -0
- package/src/config/constants.ts +4 -0
- package/src/config/serverConfig.ts +15 -0
- package/src/core/ConfigResolver.ts +6 -0
- package/src/core/DatabaseStorage.ts +469 -0
- package/src/core/LicenseVerifier.ts +154 -0
- package/src/core/MultiAgentCoordinator.ts +239 -0
- package/src/core/Pipeline.ts +146 -15
- package/src/core/Retrivora.ts +6 -0
- package/src/core/VectorPlugin.ts +12 -3
- package/src/core/mcp.ts +261 -0
- package/src/handlers/index.ts +449 -63
- package/src/hooks/useRagChat.ts +96 -42
- package/src/hooks/useStoredMessages.ts +15 -4
- package/src/index.ts +5 -0
- package/src/llm/LLMFactory.ts +9 -1
- package/src/llm/providers/GroqProvider.ts +176 -0
- package/src/llm/providers/QwenProvider.ts +191 -0
- package/src/server.ts +7 -0
- package/src/types/chat.ts +14 -0
- package/src/types/props.ts +12 -0
- package/.env.example +0 -80
- package/LICENSE.txt +0 -21
package/dist/handlers/index.mjs
CHANGED
|
@@ -59,9 +59,9 @@ var __forAwait = (obj, it, method) => (it = obj[__knownSymbol("asyncIterator")])
|
|
|
59
59
|
function isRecord(value) {
|
|
60
60
|
return typeof value === "object" && value !== null;
|
|
61
61
|
}
|
|
62
|
-
function resolvePath(obj,
|
|
63
|
-
if (!
|
|
64
|
-
return
|
|
62
|
+
function resolvePath(obj, path2) {
|
|
63
|
+
if (!path2 || !obj) return void 0;
|
|
64
|
+
return path2.replace(/\[(\w+)\]/g, ".$1").replace(/^\./, "").split(".").reduce((current, segment) => {
|
|
65
65
|
if (!isRecord(current) && !Array.isArray(current)) {
|
|
66
66
|
return void 0;
|
|
67
67
|
}
|
|
@@ -171,7 +171,7 @@ var init_PineconeProvider = __esm({
|
|
|
171
171
|
static getHealthChecker() {
|
|
172
172
|
return {
|
|
173
173
|
async check(config) {
|
|
174
|
-
var
|
|
174
|
+
var _a2, _b;
|
|
175
175
|
const opts = config.options || {};
|
|
176
176
|
const indexName = config.indexName;
|
|
177
177
|
const timestamp = Date.now();
|
|
@@ -179,7 +179,7 @@ var init_PineconeProvider = __esm({
|
|
|
179
179
|
const { Pinecone: Pinecone2 } = await import("@pinecone-database/pinecone");
|
|
180
180
|
const client = new Pinecone2({ apiKey: opts.apiKey });
|
|
181
181
|
const indexes = await client.listIndexes();
|
|
182
|
-
const indexNames = (_b = (
|
|
182
|
+
const indexNames = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
183
183
|
if (!indexNames.includes(indexName)) {
|
|
184
184
|
return {
|
|
185
185
|
healthy: false,
|
|
@@ -206,10 +206,10 @@ var init_PineconeProvider = __esm({
|
|
|
206
206
|
};
|
|
207
207
|
}
|
|
208
208
|
async initialize() {
|
|
209
|
-
var
|
|
209
|
+
var _a2, _b;
|
|
210
210
|
this.client = new Pinecone({ apiKey: this.apiKey });
|
|
211
211
|
const indexes = await this.client.listIndexes();
|
|
212
|
-
const names = (_b = (
|
|
212
|
+
const names = (_b = (_a2 = indexes.indexes) == null ? void 0 : _a2.map((i) => i.name)) != null ? _b : [];
|
|
213
213
|
if (!names.includes(this.indexName)) {
|
|
214
214
|
throw new Error(
|
|
215
215
|
`[PineconeProvider] Index "${this.indexName}" not found. Available: ${names.join(", ")}`
|
|
@@ -221,12 +221,12 @@ var init_PineconeProvider = __esm({
|
|
|
221
221
|
return namespace ? idx.namespace(namespace) : idx.namespace("");
|
|
222
222
|
}
|
|
223
223
|
async upsert(doc, namespace) {
|
|
224
|
-
var
|
|
224
|
+
var _a2;
|
|
225
225
|
await this.index(namespace).upsert({
|
|
226
226
|
records: [{
|
|
227
227
|
id: String(doc.id),
|
|
228
228
|
values: doc.vector,
|
|
229
|
-
metadata: __spreadValues({ content: doc.content }, (
|
|
229
|
+
metadata: __spreadValues({ content: doc.content }, (_a2 = doc.metadata) != null ? _a2 : {})
|
|
230
230
|
}]
|
|
231
231
|
});
|
|
232
232
|
}
|
|
@@ -234,29 +234,29 @@ var init_PineconeProvider = __esm({
|
|
|
234
234
|
const BATCH = 100;
|
|
235
235
|
for (let i = 0; i < docs.length; i += BATCH) {
|
|
236
236
|
const records = docs.slice(i, i + BATCH).map((d) => {
|
|
237
|
-
var
|
|
237
|
+
var _a2;
|
|
238
238
|
return {
|
|
239
239
|
id: String(d.id),
|
|
240
240
|
values: d.vector,
|
|
241
|
-
metadata: __spreadValues({ content: d.content }, (
|
|
241
|
+
metadata: __spreadValues({ content: d.content }, (_a2 = d.metadata) != null ? _a2 : {})
|
|
242
242
|
};
|
|
243
243
|
});
|
|
244
244
|
await this.index(namespace).upsert({ records });
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
async query(vector, topK, namespace, filter) {
|
|
248
|
-
var
|
|
248
|
+
var _a2;
|
|
249
249
|
const pineconeFilter = this.sanitizeFilter(filter);
|
|
250
250
|
const result = await this.index(namespace).query(__spreadValues({
|
|
251
251
|
vector,
|
|
252
252
|
topK,
|
|
253
253
|
includeMetadata: true
|
|
254
254
|
}, Object.keys(pineconeFilter).length > 0 ? { filter: pineconeFilter } : {}));
|
|
255
|
-
return ((
|
|
256
|
-
var
|
|
255
|
+
return ((_a2 = result.matches) != null ? _a2 : []).map((m) => {
|
|
256
|
+
var _a3, _b;
|
|
257
257
|
return {
|
|
258
258
|
id: m.id,
|
|
259
|
-
score: (
|
|
259
|
+
score: (_a3 = m.score) != null ? _a3 : 0,
|
|
260
260
|
content: ((_b = m.metadata) == null ? void 0 : _b.content) || "",
|
|
261
261
|
metadata: m.metadata
|
|
262
262
|
};
|
|
@@ -295,13 +295,13 @@ var init_PostgreSQLProvider = __esm({
|
|
|
295
295
|
init_BaseVectorProvider();
|
|
296
296
|
PostgreSQLProvider = class extends BaseVectorProvider {
|
|
297
297
|
constructor(config) {
|
|
298
|
-
var
|
|
298
|
+
var _a2;
|
|
299
299
|
super(config);
|
|
300
300
|
this.tableName = this.indexName.replace(/[^a-z0-9_]/gi, "_");
|
|
301
301
|
const opts = config.options;
|
|
302
302
|
if (!opts.connectionString) throw new Error("[PostgreSQLProvider] options.connectionString is required");
|
|
303
303
|
this.connectionString = opts.connectionString;
|
|
304
|
-
this.dimensions = (
|
|
304
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 1536;
|
|
305
305
|
}
|
|
306
306
|
static getValidator() {
|
|
307
307
|
return {
|
|
@@ -382,7 +382,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
384
|
async upsert(doc, namespace = "") {
|
|
385
|
-
var
|
|
385
|
+
var _a2;
|
|
386
386
|
const vectorLiteral = `[${doc.vector.join(",")}]`;
|
|
387
387
|
await this.pool.query(
|
|
388
388
|
`INSERT INTO ${this.tableName} (id, namespace, content, metadata, embedding)
|
|
@@ -392,7 +392,7 @@ var init_PostgreSQLProvider = __esm({
|
|
|
392
392
|
content = EXCLUDED.content,
|
|
393
393
|
metadata = EXCLUDED.metadata,
|
|
394
394
|
embedding = EXCLUDED.embedding`,
|
|
395
|
-
[doc.id, namespace, doc.content, JSON.stringify((
|
|
395
|
+
[doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), vectorLiteral]
|
|
396
396
|
);
|
|
397
397
|
}
|
|
398
398
|
async batchUpsert(docs, namespace = "") {
|
|
@@ -405,9 +405,9 @@ var init_PostgreSQLProvider = __esm({
|
|
|
405
405
|
const batch = docs.slice(i, i + BATCH_SIZE);
|
|
406
406
|
const values = [];
|
|
407
407
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
408
|
-
var
|
|
408
|
+
var _a2;
|
|
409
409
|
const offset = idx * 5;
|
|
410
|
-
values.push(doc.id, namespace, doc.content, JSON.stringify((
|
|
410
|
+
values.push(doc.id, namespace, doc.content, JSON.stringify((_a2 = doc.metadata) != null ? _a2 : {}), `[${doc.vector.join(",")}]`);
|
|
411
411
|
return `($${offset + 1}, $${offset + 2}, $${offset + 3}, $${offset + 4}, $${offset + 5}::vector)`;
|
|
412
412
|
}).join(", ");
|
|
413
413
|
const query = `
|
|
@@ -490,8 +490,8 @@ var init_PostgreSQLProvider = __esm({
|
|
|
490
490
|
|
|
491
491
|
// src/utils/synonyms.ts
|
|
492
492
|
function resolveMetadataValue(meta, uiKey) {
|
|
493
|
-
var
|
|
494
|
-
const synonyms = (
|
|
493
|
+
var _a2;
|
|
494
|
+
const synonyms = (_a2 = FIELD_SYNONYMS[uiKey]) != null ? _a2 : [];
|
|
495
495
|
const keys = Object.keys(meta);
|
|
496
496
|
const systemKeys = ["namespace", "filename", "filesize", "filetype", "docid", "uploadedat", "dimension", "chunkindex"];
|
|
497
497
|
let match = keys.find((k) => k.toLowerCase() === uiKey.toLowerCase());
|
|
@@ -578,14 +578,14 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
578
578
|
init_synonyms();
|
|
579
579
|
MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
580
580
|
constructor(config) {
|
|
581
|
-
var
|
|
581
|
+
var _a2, _b, _c;
|
|
582
582
|
super(config);
|
|
583
583
|
const opts = config.options || {};
|
|
584
584
|
if (!opts.connectionString) {
|
|
585
585
|
throw new Error("[MultiTablePostgresProvider] options.connectionString is required");
|
|
586
586
|
}
|
|
587
587
|
this.connectionString = opts.connectionString;
|
|
588
|
-
this.dimensions = (
|
|
588
|
+
this.dimensions = (_a2 = opts.dimensions) != null ? _a2 : 768;
|
|
589
589
|
this.tables = [];
|
|
590
590
|
const rawSearchFields = (_c = (_b = opts.searchFields) != null ? _b : process.env.VECTOR_DB_SEARCH_FIELDS) != null ? _c : ["name", "product_name", "productname", "title"];
|
|
591
591
|
this.searchFields = typeof rawSearchFields === "string" ? rawSearchFields.split(",").map((f) => f.trim()).filter(Boolean) : rawSearchFields;
|
|
@@ -643,11 +643,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
643
643
|
* Batch upsert documents by dynamically provisioning tables and columns based on CSV headers.
|
|
644
644
|
*/
|
|
645
645
|
async batchUpsert(docs, namespace = "") {
|
|
646
|
-
var
|
|
646
|
+
var _a2;
|
|
647
647
|
if (docs.length === 0) return;
|
|
648
648
|
const docsByFile = {};
|
|
649
649
|
for (const doc of docs) {
|
|
650
|
-
const fileName = ((
|
|
650
|
+
const fileName = ((_a2 = doc.metadata) == null ? void 0 : _a2.fileName) || this.uploadTable;
|
|
651
651
|
if (!docsByFile[fileName]) docsByFile[fileName] = [];
|
|
652
652
|
docsByFile[fileName].push(doc);
|
|
653
653
|
}
|
|
@@ -700,11 +700,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
700
700
|
const headerColumns = csvHeaders.map((h) => `"${h}"`).join(", ");
|
|
701
701
|
const allColumns = `id, ${headerColumns ? headerColumns + ", " : ""}namespace, content, metadata, embedding`;
|
|
702
702
|
const valuePlaceholders = batch.map((doc, idx) => {
|
|
703
|
-
var
|
|
703
|
+
var _a3, _b;
|
|
704
704
|
const offset = idx * (5 + csvHeaders.length);
|
|
705
705
|
values.push(doc.id);
|
|
706
706
|
for (const h of csvHeaders) {
|
|
707
|
-
values.push(String(((
|
|
707
|
+
values.push(String(((_a3 = doc.metadata) == null ? void 0 : _a3[h]) || ""));
|
|
708
708
|
}
|
|
709
709
|
values.push(namespace, doc.content, JSON.stringify((_b = doc.metadata) != null ? _b : {}), `[${doc.vector.join(",")}]`);
|
|
710
710
|
const docPlaceholders = [];
|
|
@@ -743,7 +743,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
743
743
|
* Query all configured tables and merge results, sorted by cosine similarity score.
|
|
744
744
|
*/
|
|
745
745
|
async query(vector, topK, _namespace, _filter) {
|
|
746
|
-
var
|
|
746
|
+
var _a2;
|
|
747
747
|
if (!this.pool) {
|
|
748
748
|
throw new Error("[MultiTablePostgresProvider] Provider not initialized. Call initialize() first.");
|
|
749
749
|
}
|
|
@@ -774,11 +774,11 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
774
774
|
const filterParams = [];
|
|
775
775
|
if (metadataFilters && Object.keys(metadataFilters).length > 0) {
|
|
776
776
|
const conditions = Object.entries(metadataFilters).map(([key, val]) => {
|
|
777
|
-
var
|
|
777
|
+
var _a4;
|
|
778
778
|
filterParams.push(String(val));
|
|
779
779
|
const baseOffset = queryText && dynamicKeywordQuery ? 2 : 1;
|
|
780
780
|
const paramIdx = baseOffset + filterParams.length;
|
|
781
|
-
const synonyms = (
|
|
781
|
+
const synonyms = (_a4 = FIELD_SYNONYMS[key]) != null ? _a4 : [];
|
|
782
782
|
const keysToCheck = [key, ...synonyms];
|
|
783
783
|
const coalesceExprs = keysToCheck.flatMap((k) => [
|
|
784
784
|
`metadata->>'${k}'`,
|
|
@@ -847,7 +847,7 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
847
847
|
}
|
|
848
848
|
const tableResults = [];
|
|
849
849
|
for (const row of result.rows) {
|
|
850
|
-
const
|
|
850
|
+
const _a3 = row, { hybrid_score, id } = _a3, rest = __objRest(_a3, ["hybrid_score", "id"]);
|
|
851
851
|
delete rest.embedding;
|
|
852
852
|
delete rest.vector_score;
|
|
853
853
|
delete rest.keyword_score;
|
|
@@ -876,10 +876,10 @@ var init_MultiTablePostgresProvider = __esm({
|
|
|
876
876
|
}
|
|
877
877
|
allResults.sort((a, b) => b.score - a.score);
|
|
878
878
|
if (allResults.length === 0) return [];
|
|
879
|
-
const bestMatchTable = (
|
|
879
|
+
const bestMatchTable = (_a2 = allResults[0].metadata) == null ? void 0 : _a2.source_table;
|
|
880
880
|
const finalSorted = allResults.filter((res) => {
|
|
881
|
-
var
|
|
882
|
-
return ((
|
|
881
|
+
var _a3;
|
|
882
|
+
return ((_a3 = res.metadata) == null ? void 0 : _a3.source_table) === bestMatchTable;
|
|
883
883
|
});
|
|
884
884
|
console.log(`[MultiTablePostgresProvider] --- Search Complete ---`);
|
|
885
885
|
console.log(`[MultiTablePostgresProvider] Final top match from "${bestMatchTable}" with score ${finalSorted[0].score.toFixed(4)}`);
|
|
@@ -1284,14 +1284,14 @@ var init_QdrantProvider = __esm({
|
|
|
1284
1284
|
* Samples points from the collection to discover available payload fields.
|
|
1285
1285
|
*/
|
|
1286
1286
|
async discoverSchema() {
|
|
1287
|
-
var
|
|
1287
|
+
var _a2;
|
|
1288
1288
|
try {
|
|
1289
1289
|
const { data } = await this.http.post(`/collections/${this.indexName}/points/scroll`, {
|
|
1290
1290
|
limit: 20,
|
|
1291
1291
|
with_payload: true,
|
|
1292
1292
|
with_vector: false
|
|
1293
1293
|
});
|
|
1294
|
-
const points = ((
|
|
1294
|
+
const points = ((_a2 = data.result) == null ? void 0 : _a2.points) || [];
|
|
1295
1295
|
const keys = /* @__PURE__ */ new Set();
|
|
1296
1296
|
for (const point of points) {
|
|
1297
1297
|
const payload = point.payload || {};
|
|
@@ -1317,12 +1317,12 @@ var init_QdrantProvider = __esm({
|
|
|
1317
1317
|
* Ensures the collection exists. Creates it if missing.
|
|
1318
1318
|
*/
|
|
1319
1319
|
async ensureCollection() {
|
|
1320
|
-
var
|
|
1320
|
+
var _a2;
|
|
1321
1321
|
try {
|
|
1322
1322
|
await this.http.get(`/collections/${this.indexName}`);
|
|
1323
1323
|
console.log(`[QdrantProvider] \u2705 Collection "${this.indexName}" already exists.`);
|
|
1324
1324
|
} catch (err) {
|
|
1325
|
-
if (axios4.isAxiosError(err) && ((
|
|
1325
|
+
if (axios4.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1326
1326
|
const opts = this.config.options;
|
|
1327
1327
|
const dimensionsForCreate = opts.dimensions || 1536;
|
|
1328
1328
|
console.log(`[QdrantProvider] \u23F3 Creating collection "${this.indexName}" (dimensions: ${dimensionsForCreate})...`);
|
|
@@ -1342,7 +1342,7 @@ var init_QdrantProvider = __esm({
|
|
|
1342
1342
|
* Ensures that a payload field has an index.
|
|
1343
1343
|
*/
|
|
1344
1344
|
async ensureIndex(fieldName, schema = "keyword") {
|
|
1345
|
-
var
|
|
1345
|
+
var _a2;
|
|
1346
1346
|
let fullPath = fieldName;
|
|
1347
1347
|
if (!this.isFlatPayload && !fieldName.includes(".") && fieldName !== "namespace" && fieldName !== this.contentField) {
|
|
1348
1348
|
fullPath = `${this.metadataField}.${fieldName}`;
|
|
@@ -1355,7 +1355,7 @@ var init_QdrantProvider = __esm({
|
|
|
1355
1355
|
console.log(`[QdrantProvider] \u2705 Ensured ${schema} index for "${fullPath}"`);
|
|
1356
1356
|
} catch (err) {
|
|
1357
1357
|
let status;
|
|
1358
|
-
if (axios4.isAxiosError(err)) status = (
|
|
1358
|
+
if (axios4.isAxiosError(err)) status = (_a2 = err.response) == null ? void 0 : _a2.status;
|
|
1359
1359
|
if (status === 409) return;
|
|
1360
1360
|
console.warn(`[QdrantProvider] \u26A0\uFE0F Could not ensure index for "${fullPath}":`, err instanceof Error ? err.message : String(err));
|
|
1361
1361
|
}
|
|
@@ -1384,7 +1384,7 @@ var init_QdrantProvider = __esm({
|
|
|
1384
1384
|
await this.http.put(`/collections/${this.indexName}/points`, payload);
|
|
1385
1385
|
}
|
|
1386
1386
|
async query(vector, topK, namespace, _filter) {
|
|
1387
|
-
var
|
|
1387
|
+
var _a2;
|
|
1388
1388
|
const must = [];
|
|
1389
1389
|
if (namespace) {
|
|
1390
1390
|
must.push({ key: "namespace", match: { value: namespace } });
|
|
@@ -1406,7 +1406,7 @@ var init_QdrantProvider = __esm({
|
|
|
1406
1406
|
limit: topK,
|
|
1407
1407
|
with_payload: true,
|
|
1408
1408
|
params: {
|
|
1409
|
-
hnsw_ef: ((
|
|
1409
|
+
hnsw_ef: ((_a2 = this.config.options) == null ? void 0 : _a2.efSearch) || Math.max(topK * 20, 128),
|
|
1410
1410
|
exact: false
|
|
1411
1411
|
},
|
|
1412
1412
|
filter: must.length > 0 ? { must } : void 0
|
|
@@ -1501,13 +1501,13 @@ var init_ChromaDBProvider = __esm({
|
|
|
1501
1501
|
* Get or create the ChromaDB collection.
|
|
1502
1502
|
*/
|
|
1503
1503
|
async initialize() {
|
|
1504
|
-
var
|
|
1504
|
+
var _a2;
|
|
1505
1505
|
try {
|
|
1506
1506
|
const { data } = await this.http.get(`/api/v1/collections/${this.indexName}`);
|
|
1507
1507
|
this.collectionId = data.id;
|
|
1508
1508
|
console.log(`[ChromaDBProvider] \u2705 Collection "${this.indexName}" found (id: ${this.collectionId})`);
|
|
1509
1509
|
} catch (err) {
|
|
1510
|
-
if (axios5.isAxiosError(err) && ((
|
|
1510
|
+
if (axios5.isAxiosError(err) && ((_a2 = err.response) == null ? void 0 : _a2.status) === 404) {
|
|
1511
1511
|
console.log(`[ChromaDBProvider] \u23F3 Collection "${this.indexName}" not found. Creating...`);
|
|
1512
1512
|
const { data } = await this.http.post("/api/v1/collections", {
|
|
1513
1513
|
name: this.indexName
|
|
@@ -1728,7 +1728,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1728
1728
|
await this.http.post("/v1/batch/objects", payload);
|
|
1729
1729
|
}
|
|
1730
1730
|
async query(vector, topK, namespace, _filter) {
|
|
1731
|
-
var
|
|
1731
|
+
var _a2, _b;
|
|
1732
1732
|
const queryText = _filter == null ? void 0 : _filter.queryText;
|
|
1733
1733
|
const sanitizedFilter = this.sanitizeFilter(_filter);
|
|
1734
1734
|
const searchParams = queryText ? `hybrid: { query: ${JSON.stringify(queryText)}, alpha: 0.5 }` : `nearVector: { vector: ${JSON.stringify(vector)} }`;
|
|
@@ -1754,7 +1754,7 @@ var init_WeaviateProvider = __esm({
|
|
|
1754
1754
|
`
|
|
1755
1755
|
};
|
|
1756
1756
|
const { data } = await this.http.post("/v1/graphql", graphqlQuery);
|
|
1757
|
-
const results = ((_b = (
|
|
1757
|
+
const results = ((_b = (_a2 = data.data) == null ? void 0 : _a2.Get) == null ? void 0 : _b[this.indexName]) || [];
|
|
1758
1758
|
return results.map((res) => ({
|
|
1759
1759
|
id: res["_additional"].id,
|
|
1760
1760
|
score: 1 - res["_additional"].distance,
|
|
@@ -1807,10 +1807,10 @@ var init_WeaviateProvider = __esm({
|
|
|
1807
1807
|
return `{ operator: And, operands: [${operands.join(", ")}] }`;
|
|
1808
1808
|
}
|
|
1809
1809
|
weaviateOperand(key, value) {
|
|
1810
|
-
const
|
|
1811
|
-
if (typeof value === "number") return `{ ${
|
|
1812
|
-
if (typeof value === "boolean") return `{ ${
|
|
1813
|
-
return `{ ${
|
|
1810
|
+
const path2 = `path: [${JSON.stringify(key)}], operator: Equal`;
|
|
1811
|
+
if (typeof value === "number") return `{ ${path2}, valueNumber: ${value} }`;
|
|
1812
|
+
if (typeof value === "boolean") return `{ ${path2}, valueBoolean: ${value} }`;
|
|
1813
|
+
return `{ ${path2}, valueString: ${JSON.stringify(value)} }`;
|
|
1814
1814
|
}
|
|
1815
1815
|
};
|
|
1816
1816
|
}
|
|
@@ -1837,21 +1837,21 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1837
1837
|
}
|
|
1838
1838
|
}
|
|
1839
1839
|
async initialize() {
|
|
1840
|
-
var
|
|
1840
|
+
var _a2;
|
|
1841
1841
|
this.http = axios8.create({
|
|
1842
1842
|
baseURL: this.opts.baseUrl,
|
|
1843
1843
|
headers: __spreadValues({
|
|
1844
1844
|
"Content-Type": "application/json"
|
|
1845
1845
|
}, this.opts.headers),
|
|
1846
|
-
timeout: (
|
|
1846
|
+
timeout: (_a2 = this.opts.timeout) != null ? _a2 : 3e4
|
|
1847
1847
|
});
|
|
1848
1848
|
if (!await this.ping()) {
|
|
1849
1849
|
throw new Error(`[UniversalVectorProvider] Failed to connect to ${this.opts.baseUrl}`);
|
|
1850
1850
|
}
|
|
1851
1851
|
}
|
|
1852
1852
|
async upsert(doc, namespace) {
|
|
1853
|
-
var
|
|
1854
|
-
const endpoint = (
|
|
1853
|
+
var _a2, _b, _c;
|
|
1854
|
+
const endpoint = (_a2 = this.opts.upsertEndpoint) != null ? _a2 : "/upsert";
|
|
1855
1855
|
const template = (_b = this.opts.upsertTemplate) != null ? _b : JSON.stringify({
|
|
1856
1856
|
id: "{{id}}",
|
|
1857
1857
|
vector: "{{vector}}",
|
|
@@ -1884,8 +1884,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1884
1884
|
}
|
|
1885
1885
|
}
|
|
1886
1886
|
async query(vector, topK, namespace, filter) {
|
|
1887
|
-
var
|
|
1888
|
-
const endpoint = (
|
|
1887
|
+
var _a2, _b;
|
|
1888
|
+
const endpoint = (_a2 = this.opts.queryEndpoint) != null ? _a2 : "/query";
|
|
1889
1889
|
const template = (_b = this.opts.queryTemplate) != null ? _b : JSON.stringify({
|
|
1890
1890
|
vector: "{{vector}}",
|
|
1891
1891
|
limit: "{{topK}}",
|
|
@@ -1911,12 +1911,12 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1911
1911
|
);
|
|
1912
1912
|
}
|
|
1913
1913
|
return results.map((item) => {
|
|
1914
|
-
var
|
|
1914
|
+
var _a3, _b2, _c, _d, _e, _f, _g2;
|
|
1915
1915
|
return {
|
|
1916
|
-
id: item[(
|
|
1916
|
+
id: item[(_a3 = this.opts.queryIdField) != null ? _a3 : "id"],
|
|
1917
1917
|
score: (_c = item[(_b2 = this.opts.queryScoreField) != null ? _b2 : "score"]) != null ? _c : 0,
|
|
1918
1918
|
content: (_e = item[(_d = this.opts.queryContentField) != null ? _d : "content"]) != null ? _e : "",
|
|
1919
|
-
metadata: (
|
|
1919
|
+
metadata: (_g2 = item[(_f = this.opts.queryMetadataField) != null ? _f : "metadata"]) != null ? _g2 : {}
|
|
1920
1920
|
};
|
|
1921
1921
|
});
|
|
1922
1922
|
} catch (error) {
|
|
@@ -1926,8 +1926,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1926
1926
|
}
|
|
1927
1927
|
}
|
|
1928
1928
|
async delete(id, namespace) {
|
|
1929
|
-
var
|
|
1930
|
-
const endpoint = (
|
|
1929
|
+
var _a2, _b;
|
|
1930
|
+
const endpoint = (_a2 = this.opts.deleteEndpoint) != null ? _a2 : "/delete";
|
|
1931
1931
|
const template = (_b = this.opts.deleteTemplate) != null ? _b : JSON.stringify({
|
|
1932
1932
|
id: "{{id}}",
|
|
1933
1933
|
namespace: "{{namespace}}"
|
|
@@ -1945,8 +1945,8 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1945
1945
|
}
|
|
1946
1946
|
}
|
|
1947
1947
|
async deleteNamespace(namespace) {
|
|
1948
|
-
var
|
|
1949
|
-
const endpoint = (
|
|
1948
|
+
var _a2;
|
|
1949
|
+
const endpoint = (_a2 = this.opts.deleteNamespaceEndpoint) != null ? _a2 : "/delete-namespace";
|
|
1950
1950
|
try {
|
|
1951
1951
|
await this.http.post(endpoint, { namespace });
|
|
1952
1952
|
} catch (error) {
|
|
@@ -1956,9 +1956,9 @@ var init_UniversalVectorProvider = __esm({
|
|
|
1956
1956
|
}
|
|
1957
1957
|
}
|
|
1958
1958
|
async ping() {
|
|
1959
|
-
var
|
|
1959
|
+
var _a2;
|
|
1960
1960
|
try {
|
|
1961
|
-
const endpoint = (
|
|
1961
|
+
const endpoint = (_a2 = this.opts.pingEndpoint) != null ? _a2 : "/health";
|
|
1962
1962
|
const response = await this.http.get(endpoint, { timeout: 5e3 });
|
|
1963
1963
|
return response.status >= 200 && response.status < 300;
|
|
1964
1964
|
} catch (e) {
|
|
@@ -2072,6 +2072,8 @@ var LLM_PROVIDERS = [
|
|
|
2072
2072
|
"anthropic",
|
|
2073
2073
|
"ollama",
|
|
2074
2074
|
"gemini",
|
|
2075
|
+
"groq",
|
|
2076
|
+
"qwen",
|
|
2075
2077
|
"rest",
|
|
2076
2078
|
"universal_rest",
|
|
2077
2079
|
"custom"
|
|
@@ -2080,6 +2082,7 @@ var EMBEDDING_PROVIDERS = [
|
|
|
2080
2082
|
"openai",
|
|
2081
2083
|
"ollama",
|
|
2082
2084
|
"gemini",
|
|
2085
|
+
"qwen",
|
|
2083
2086
|
"rest",
|
|
2084
2087
|
"universal_rest",
|
|
2085
2088
|
"custom"
|
|
@@ -2088,6 +2091,7 @@ var PROVIDERS_WITH_EMBEDDINGS = [
|
|
|
2088
2091
|
"openai",
|
|
2089
2092
|
"ollama",
|
|
2090
2093
|
"gemini",
|
|
2094
|
+
"qwen",
|
|
2091
2095
|
"rest",
|
|
2092
2096
|
"universal_rest"
|
|
2093
2097
|
];
|
|
@@ -2095,8 +2099,8 @@ var UI_BORDER_RADIUS_OPTIONS = ["none", "sm", "md", "lg", "xl", "full"];
|
|
|
2095
2099
|
|
|
2096
2100
|
// src/config/serverConfig.ts
|
|
2097
2101
|
function readString(env, name) {
|
|
2098
|
-
var
|
|
2099
|
-
const value = (
|
|
2102
|
+
var _a2;
|
|
2103
|
+
const value = (_a2 = env[name]) == null ? void 0 : _a2.trim();
|
|
2100
2104
|
return value ? value : void 0;
|
|
2101
2105
|
}
|
|
2102
2106
|
function readNumber(env, name, fallback) {
|
|
@@ -2109,23 +2113,23 @@ function readNumber(env, name, fallback) {
|
|
|
2109
2113
|
return parsed;
|
|
2110
2114
|
}
|
|
2111
2115
|
function readEnum(env, name, fallback, allowed) {
|
|
2112
|
-
var
|
|
2113
|
-
const value = (
|
|
2116
|
+
var _a2;
|
|
2117
|
+
const value = (_a2 = readString(env, name)) != null ? _a2 : fallback;
|
|
2114
2118
|
if (allowed.includes(value)) {
|
|
2115
2119
|
return value;
|
|
2116
2120
|
}
|
|
2117
2121
|
throw new Error(`[getRagConfig] ${name} must be one of: ${allowed.join(", ")}`);
|
|
2118
2122
|
}
|
|
2119
2123
|
function getEnvConfig(env = process.env, base) {
|
|
2120
|
-
var
|
|
2121
|
-
const projectId = (_c = (_b = (
|
|
2124
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na, _Oa, _Pa, _Qa;
|
|
2125
|
+
const projectId = (_c = (_b = (_a2 = readString(env, "RAG_PROJECT_ID")) != null ? _a2 : readString(env, "NEXT_PUBLIC_PROJECT_ID")) != null ? _b : base == null ? void 0 : base.projectId) != null ? _c : "__default__";
|
|
2122
2126
|
const vectorProvider = readEnum(env, "VECTOR_DB_PROVIDER", "pinecone", VECTOR_DB_PROVIDERS);
|
|
2123
2127
|
const llmProvider = readEnum(env, "LLM_PROVIDER", "openai", LLM_PROVIDERS);
|
|
2124
2128
|
const embeddingProvider = readEnum(env, "EMBEDDING_PROVIDER", "openai", EMBEDDING_PROVIDERS);
|
|
2125
2129
|
const embeddingDimensions = readNumber(env, "EMBEDDING_DIMENSIONS", 1536);
|
|
2126
2130
|
const vectorDbOptions = {};
|
|
2127
2131
|
if (vectorProvider === "pinecone") {
|
|
2128
|
-
vectorDbOptions.apiKey = (
|
|
2132
|
+
vectorDbOptions.apiKey = (_g2 = (_f = readString(env, "PINECONE_API_KEY")) != null ? _f : (_e = (_d = base == null ? void 0 : base.vectorDb) == null ? void 0 : _d.options) == null ? void 0 : _e.apiKey) != null ? _g2 : "";
|
|
2129
2133
|
vectorDbOptions.indexName = (_l = (_i = readString(env, "PINECONE_INDEX")) != null ? _i : (_h = base == null ? void 0 : base.vectorDb) == null ? void 0 : _h.indexName) != null ? _l : (_k = (_j = base == null ? void 0 : base.vectorDb) == null ? void 0 : _j.options) == null ? void 0 : _k.indexName;
|
|
2130
2134
|
} else if (vectorProvider === "pgvector" || vectorProvider === "postgresql") {
|
|
2131
2135
|
vectorDbOptions.connectionString = (_q = (_p = (_m = readString(env, "PGVECTOR_CONNECTION_STRING")) != null ? _m : readString(env, "POSTGRES_URL")) != null ? _p : (_o = (_n = base == null ? void 0 : base.vectorDb) == null ? void 0 : _n.options) == null ? void 0 : _o.connectionString) != null ? _q : "";
|
|
@@ -2187,17 +2191,18 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2187
2191
|
rest: "default",
|
|
2188
2192
|
custom: "default"
|
|
2189
2193
|
};
|
|
2190
|
-
return __spreadValues({
|
|
2194
|
+
return __spreadProps(__spreadValues({
|
|
2191
2195
|
projectId,
|
|
2196
|
+
licenseKey: (_ha = (_ga = readString(env, "RETRIVORA_LICENSE_KEY")) != null ? _ga : readString(env, "LICENSE_KEY")) != null ? _ha : base == null ? void 0 : base.licenseKey,
|
|
2192
2197
|
vectorDb: {
|
|
2193
2198
|
provider: vectorProvider,
|
|
2194
|
-
indexName: (
|
|
2199
|
+
indexName: (_ja = (_ia = readString(env, "VECTOR_DB_INDEX")) != null ? _ia : vectorDbOptions.indexName) != null ? _ja : "rag-index",
|
|
2195
2200
|
options: vectorDbOptions
|
|
2196
2201
|
},
|
|
2197
2202
|
llm: {
|
|
2198
2203
|
provider: llmProvider,
|
|
2199
|
-
model: (
|
|
2200
|
-
apiKey: (
|
|
2204
|
+
model: (_la = (_ka = readString(env, "LLM_MODEL")) != null ? _ka : DEFAULT_MODEL_BY_PROVIDER[llmProvider]) != null ? _la : "gpt-4o",
|
|
2205
|
+
apiKey: (_ma = llmApiKeyByProvider[llmProvider]) != null ? _ma : "",
|
|
2201
2206
|
baseUrl: readString(env, "LLM_BASE_URL"),
|
|
2202
2207
|
systemPrompt: readString(env, "LLM_SYSTEM_PROMPT"),
|
|
2203
2208
|
maxTokens: readNumber(env, "LLM_MAX_TOKENS", 4096),
|
|
@@ -2210,7 +2215,7 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2210
2215
|
},
|
|
2211
2216
|
embedding: {
|
|
2212
2217
|
provider: embeddingProvider,
|
|
2213
|
-
model: (
|
|
2218
|
+
model: (_na = readString(env, "EMBEDDING_MODEL")) != null ? _na : "text-embedding-3-small",
|
|
2214
2219
|
apiKey: embeddingApiKeyByProvider[embeddingProvider],
|
|
2215
2220
|
baseUrl: readString(env, "EMBEDDING_BASE_URL"),
|
|
2216
2221
|
dimensions: embeddingDimensions,
|
|
@@ -2221,30 +2226,30 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2221
2226
|
}
|
|
2222
2227
|
},
|
|
2223
2228
|
ui: {
|
|
2224
|
-
title: (
|
|
2225
|
-
subtitle: (
|
|
2226
|
-
primaryColor: (
|
|
2227
|
-
accentColor: (
|
|
2228
|
-
logoUrl: (
|
|
2229
|
-
placeholder: (
|
|
2230
|
-
showSources: ((
|
|
2231
|
-
welcomeMessage: (
|
|
2232
|
-
visualStyle: (
|
|
2233
|
-
borderRadius: (
|
|
2234
|
-
allowUpload: ((
|
|
2229
|
+
title: (_pa = (_oa = readString(env, "NEXT_PUBLIC_UI_TITLE")) != null ? _oa : readString(env, "UI_TITLE")) != null ? _pa : "AI Assistant",
|
|
2230
|
+
subtitle: (_ra = (_qa = readString(env, "NEXT_PUBLIC_UI_SUBTITLE")) != null ? _qa : readString(env, "UI_SUBTITLE")) != null ? _ra : "Powered by RAG",
|
|
2231
|
+
primaryColor: (_ta = (_sa = readString(env, "NEXT_PUBLIC_PRIMARY_COLOR")) != null ? _sa : readString(env, "UI_PRIMARY_COLOR")) != null ? _ta : "#10b981",
|
|
2232
|
+
accentColor: (_va = (_ua = readString(env, "NEXT_PUBLIC_ACCENT_COLOR")) != null ? _ua : readString(env, "UI_ACCENT_COLOR")) != null ? _va : "#3b82f6",
|
|
2233
|
+
logoUrl: (_wa = readString(env, "NEXT_PUBLIC_LOGO_URL")) != null ? _wa : readString(env, "UI_LOGO_URL"),
|
|
2234
|
+
placeholder: (_ya = (_xa = readString(env, "NEXT_PUBLIC_PLACEHOLDER")) != null ? _xa : readString(env, "UI_PLACEHOLDER")) != null ? _ya : "Ask me anything\u2026",
|
|
2235
|
+
showSources: ((_Aa = (_za = readString(env, "NEXT_PUBLIC_SHOW_SOURCES")) != null ? _za : readString(env, "UI_SHOW_SOURCES")) != null ? _Aa : "true") !== "false",
|
|
2236
|
+
welcomeMessage: (_Ca = (_Ba = readString(env, "NEXT_PUBLIC_WELCOME_MESSAGE")) != null ? _Ba : readString(env, "UI_WELCOME_MESSAGE")) != null ? _Ca : "Hello! I'm your AI assistant. Ask me anything about your documents.",
|
|
2237
|
+
visualStyle: (_Ea = (_Da = readString(env, "NEXT_PUBLIC_UI_VISUAL_STYLE")) != null ? _Da : readString(env, "UI_VISUAL_STYLE")) != null ? _Ea : "glass",
|
|
2238
|
+
borderRadius: (_Ga = (_Fa = readString(env, "NEXT_PUBLIC_UI_BORDER_RADIUS")) != null ? _Fa : readString(env, "UI_BORDER_RADIUS")) != null ? _Ga : "xl",
|
|
2239
|
+
allowUpload: ((_Ia = (_Ha = readString(env, "NEXT_PUBLIC_ALLOW_UPLOAD")) != null ? _Ha : readString(env, "UI_ALLOW_UPLOAD")) != null ? _Ia : "false") === "true"
|
|
2235
2240
|
},
|
|
2236
2241
|
rag: {
|
|
2237
2242
|
topK: readNumber(env, "RAG_TOP_K", 5),
|
|
2238
2243
|
scoreThreshold: readNumber(env, "RAG_SCORE_THRESHOLD", 0),
|
|
2239
2244
|
chunkSize: readNumber(env, "RAG_CHUNK_SIZE", 1e3),
|
|
2240
2245
|
chunkOverlap: readNumber(env, "RAG_CHUNK_OVERLAP", 200),
|
|
2241
|
-
filterableFields: (
|
|
2246
|
+
filterableFields: (_Ja = readString(env, "RAG_FILTERABLE_FIELDS")) == null ? void 0 : _Ja.split(",").map((f) => f.trim()),
|
|
2242
2247
|
// Query pipeline toggles — read from .env.local
|
|
2243
2248
|
useQueryTransformation: readString(env, "RAG_USE_QUERY_TRANSFORMATION") === "true",
|
|
2244
2249
|
useReranking: readString(env, "RAG_USE_RERANKING") === "true",
|
|
2245
2250
|
useGraphRetrieval: readString(env, "RAG_USE_GRAPH_RETRIEVAL") === "true",
|
|
2246
|
-
architecture: (
|
|
2247
|
-
chunkingStrategy: (
|
|
2251
|
+
architecture: (_Ka = readString(env, "RAG_ARCHITECTURE")) != null ? _Ka : "simple",
|
|
2252
|
+
chunkingStrategy: (_La = readString(env, "RAG_CHUNKING_STRATEGY")) != null ? _La : "recursive",
|
|
2248
2253
|
uiMapping: (() => {
|
|
2249
2254
|
const raw = readString(env, "RAG_UI_MAPPING");
|
|
2250
2255
|
if (!raw) return void 0;
|
|
@@ -2254,6 +2259,10 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2254
2259
|
return void 0;
|
|
2255
2260
|
}
|
|
2256
2261
|
})()
|
|
2262
|
+
},
|
|
2263
|
+
telemetry: {
|
|
2264
|
+
enabled: readString(env, "TELEMETRY_ENABLED") === "true" || readString(env, "NEXT_PUBLIC_TELEMETRY_ENABLED") === "true" || ((_Ma = base == null ? void 0 : base.telemetry) == null ? void 0 : _Ma.enabled) || false,
|
|
2265
|
+
url: (_Qa = (_Pa = (_Na = readString(env, "TELEMETRY_URL")) != null ? _Na : readString(env, "NEXT_PUBLIC_TELEMETRY_URL")) != null ? _Pa : (_Oa = base == null ? void 0 : base.telemetry) == null ? void 0 : _Oa.url) != null ? _Qa : "/api/telemetry"
|
|
2257
2266
|
}
|
|
2258
2267
|
}, readString(env, "GRAPH_DB_PROVIDER") ? {
|
|
2259
2268
|
graphDb: {
|
|
@@ -2264,7 +2273,19 @@ function getEnvConfig(env = process.env, base) {
|
|
|
2264
2273
|
password: readString(env, "GRAPH_DB_PASSWORD")
|
|
2265
2274
|
}
|
|
2266
2275
|
}
|
|
2267
|
-
} : {})
|
|
2276
|
+
} : {}), {
|
|
2277
|
+
mcpServers: (() => {
|
|
2278
|
+
var _a3;
|
|
2279
|
+
const raw = (_a3 = readString(env, "MCP_SERVERS")) != null ? _a3 : readString(env, "NEXT_PUBLIC_MCP_SERVERS");
|
|
2280
|
+
if (!raw) return void 0;
|
|
2281
|
+
try {
|
|
2282
|
+
return JSON.parse(raw);
|
|
2283
|
+
} catch (e) {
|
|
2284
|
+
console.warn("[serverConfig] Failed to parse MCP_SERVERS env:", e);
|
|
2285
|
+
return void 0;
|
|
2286
|
+
}
|
|
2287
|
+
})()
|
|
2288
|
+
});
|
|
2268
2289
|
}
|
|
2269
2290
|
|
|
2270
2291
|
// src/core/ConfigResolver.ts
|
|
@@ -2290,7 +2311,8 @@ var ConfigResolver = class {
|
|
|
2290
2311
|
options: __spreadValues(__spreadValues({}, envConfig.embedding.options || {}), hostConfig.embedding.options || {})
|
|
2291
2312
|
}) : envConfig.embedding,
|
|
2292
2313
|
ui: hostConfig.ui ? mergeDefined(envConfig.ui, hostConfig.ui) : envConfig.ui,
|
|
2293
|
-
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag
|
|
2314
|
+
rag: hostConfig.rag ? __spreadValues(__spreadValues({}, envConfig.rag), hostConfig.rag) : envConfig.rag,
|
|
2315
|
+
telemetry: hostConfig.telemetry ? __spreadValues(__spreadValues({}, envConfig.telemetry), hostConfig.telemetry) : envConfig.telemetry
|
|
2294
2316
|
});
|
|
2295
2317
|
}
|
|
2296
2318
|
/**
|
|
@@ -2299,10 +2321,10 @@ var ConfigResolver = class {
|
|
|
2299
2321
|
* fallback behavior.
|
|
2300
2322
|
*/
|
|
2301
2323
|
static resolveUniversal(hostConfig, env = process.env) {
|
|
2302
|
-
var
|
|
2324
|
+
var _a2;
|
|
2303
2325
|
if (!hostConfig) return this.resolve(void 0, env);
|
|
2304
2326
|
const normalized = __spreadProps(__spreadValues({}, hostConfig), {
|
|
2305
|
-
vectorDb: (
|
|
2327
|
+
vectorDb: (_a2 = hostConfig.vectorDb) != null ? _a2 : hostConfig.vectorDatabase,
|
|
2306
2328
|
rag: this.mergeRetrievalWorkflow(hostConfig.rag, hostConfig.retrieval, hostConfig.workflow)
|
|
2307
2329
|
});
|
|
2308
2330
|
return this.resolve(normalized, env);
|
|
@@ -2322,11 +2344,11 @@ var ConfigResolver = class {
|
|
|
2322
2344
|
}
|
|
2323
2345
|
}
|
|
2324
2346
|
static mergeRetrievalWorkflow(rag, retrieval, workflow) {
|
|
2325
|
-
var
|
|
2347
|
+
var _a2, _b, _c, _d, _e;
|
|
2326
2348
|
if (!rag && !retrieval && !workflow) return void 0;
|
|
2327
2349
|
const normalized = __spreadValues({}, rag != null ? rag : {});
|
|
2328
2350
|
if (retrieval) {
|
|
2329
|
-
normalized.topK = (
|
|
2351
|
+
normalized.topK = (_a2 = retrieval.topK) != null ? _a2 : normalized.topK;
|
|
2330
2352
|
normalized.scoreThreshold = (_b = retrieval.scoreThreshold) != null ? _b : normalized.scoreThreshold;
|
|
2331
2353
|
normalized.useReranking = (_c = retrieval.useReranking) != null ? _c : normalized.useReranking;
|
|
2332
2354
|
if (retrieval.strategy === "hybrid") normalized.architecture = (_d = normalized.architecture) != null ? _d : "hybrid";
|
|
@@ -2408,8 +2430,8 @@ var OpenAIProvider = class {
|
|
|
2408
2430
|
const apiKey = config.apiKey;
|
|
2409
2431
|
const modelName = config.model;
|
|
2410
2432
|
try {
|
|
2411
|
-
const
|
|
2412
|
-
const client = new
|
|
2433
|
+
const OpenAI4 = await import("openai");
|
|
2434
|
+
const client = new OpenAI4.default({ apiKey });
|
|
2413
2435
|
const models = await client.models.list();
|
|
2414
2436
|
const hasModel = models.data.some((m) => m.id === modelName);
|
|
2415
2437
|
return {
|
|
@@ -2430,8 +2452,8 @@ var OpenAIProvider = class {
|
|
|
2430
2452
|
};
|
|
2431
2453
|
}
|
|
2432
2454
|
async chat(messages, context, options) {
|
|
2433
|
-
var
|
|
2434
|
-
const basePrompt = (_b = (
|
|
2455
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
2456
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2435
2457
|
const systemMessage = {
|
|
2436
2458
|
role: "system",
|
|
2437
2459
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2450,12 +2472,12 @@ var OpenAIProvider = class {
|
|
|
2450
2472
|
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
2451
2473
|
stop: options == null ? void 0 : options.stop
|
|
2452
2474
|
});
|
|
2453
|
-
return (_i = (_h = (
|
|
2475
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
2454
2476
|
}
|
|
2455
2477
|
chatStream(messages, context, options) {
|
|
2456
2478
|
return __asyncGenerator(this, null, function* () {
|
|
2457
|
-
var
|
|
2458
|
-
const basePrompt = (_b = (
|
|
2479
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2480
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
2459
2481
|
const systemMessage = {
|
|
2460
2482
|
role: "system",
|
|
2461
2483
|
content: buildSystemContent(basePrompt, context)
|
|
@@ -2481,7 +2503,7 @@ var OpenAIProvider = class {
|
|
|
2481
2503
|
try {
|
|
2482
2504
|
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
2483
2505
|
const chunk = temp.value;
|
|
2484
|
-
const content = ((_h = (
|
|
2506
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
2485
2507
|
if (content) yield content;
|
|
2486
2508
|
}
|
|
2487
2509
|
} catch (temp) {
|
|
@@ -2501,8 +2523,8 @@ var OpenAIProvider = class {
|
|
|
2501
2523
|
return results[0];
|
|
2502
2524
|
}
|
|
2503
2525
|
async batchEmbed(texts, options) {
|
|
2504
|
-
var
|
|
2505
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2526
|
+
var _a2, _b, _c, _d, _e;
|
|
2527
|
+
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "text-embedding-3-small";
|
|
2506
2528
|
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
2507
2529
|
const client = apiKey !== this.llmConfig.apiKey ? new OpenAI({ apiKey }) : this.client;
|
|
2508
2530
|
const response = await client.embeddings.create({ model, input: texts });
|
|
@@ -2579,8 +2601,8 @@ var AnthropicProvider = class {
|
|
|
2579
2601
|
};
|
|
2580
2602
|
}
|
|
2581
2603
|
async chat(messages, context, options) {
|
|
2582
|
-
var
|
|
2583
|
-
const basePrompt = (_b = (
|
|
2604
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2605
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
|
|
2584
2606
|
const system = buildSystemContent(basePrompt, context);
|
|
2585
2607
|
const anthropicMessages = messages.map((m) => ({
|
|
2586
2608
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2591,7 +2613,7 @@ var AnthropicProvider = class {
|
|
|
2591
2613
|
const extraParams = {};
|
|
2592
2614
|
if (isThinkingEnabled && isClaude37) {
|
|
2593
2615
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2594
|
-
const maxTokens = (
|
|
2616
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2595
2617
|
const budget = Math.min(
|
|
2596
2618
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2597
2619
|
maxTokens - 1
|
|
@@ -2618,8 +2640,8 @@ var AnthropicProvider = class {
|
|
|
2618
2640
|
}
|
|
2619
2641
|
chatStream(messages, context, options) {
|
|
2620
2642
|
return __asyncGenerator(this, null, function* () {
|
|
2621
|
-
var
|
|
2622
|
-
const basePrompt = (_b = (
|
|
2643
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2644
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the context below to answer the user's question accurately.";
|
|
2623
2645
|
const system = buildSystemContent(basePrompt, context);
|
|
2624
2646
|
const anthropicMessages = messages.map((m) => ({
|
|
2625
2647
|
role: m.role === "assistant" ? "assistant" : "user",
|
|
@@ -2630,7 +2652,7 @@ var AnthropicProvider = class {
|
|
|
2630
2652
|
const extraParams = {};
|
|
2631
2653
|
if (isThinkingEnabled && isClaude37) {
|
|
2632
2654
|
extraParams.betas = ["interleaved-thinking-2025-05-14"];
|
|
2633
|
-
const maxTokens = (
|
|
2655
|
+
const maxTokens = (_g2 = (_f = options == null ? void 0 : options.maxTokens) != null ? _f : this.llmConfig.maxTokens) != null ? _g2 : 4096;
|
|
2634
2656
|
const budget = Math.min(
|
|
2635
2657
|
typeof ((_h = this.llmConfig.options) == null ? void 0 : _h.thinkingBudget) === "number" ? (_i = this.llmConfig.options) == null ? void 0 : _i.thinkingBudget : 2048,
|
|
2636
2658
|
maxTokens - 1
|
|
@@ -2703,8 +2725,8 @@ var AnthropicProvider = class {
|
|
|
2703
2725
|
import axios from "axios";
|
|
2704
2726
|
var OllamaProvider = class {
|
|
2705
2727
|
constructor(llmConfig, embeddingConfig) {
|
|
2706
|
-
var
|
|
2707
|
-
const baseURL = (
|
|
2728
|
+
var _a2, _b;
|
|
2729
|
+
const baseURL = (_a2 = llmConfig.baseUrl) != null ? _a2 : "http://localhost:11434";
|
|
2708
2730
|
const timeout = Number((_b = llmConfig.options) == null ? void 0 : _b.timeout) || 3e5;
|
|
2709
2731
|
this.http = axios.create({ baseURL, timeout });
|
|
2710
2732
|
this.llmConfig = llmConfig;
|
|
@@ -2762,8 +2784,8 @@ var OllamaProvider = class {
|
|
|
2762
2784
|
};
|
|
2763
2785
|
}
|
|
2764
2786
|
async chat(messages, context, options) {
|
|
2765
|
-
var
|
|
2766
|
-
const basePrompt = (_b = (
|
|
2787
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
2788
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
|
|
2767
2789
|
const system = buildSystemContent(basePrompt, context);
|
|
2768
2790
|
const { data } = await this.http.post("/api/chat", {
|
|
2769
2791
|
model: this.llmConfig.model,
|
|
@@ -2781,8 +2803,8 @@ var OllamaProvider = class {
|
|
|
2781
2803
|
}
|
|
2782
2804
|
chatStream(messages, context, options) {
|
|
2783
2805
|
return __asyncGenerator(this, null, function* () {
|
|
2784
|
-
var
|
|
2785
|
-
const basePrompt = (_b = (
|
|
2806
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
2807
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Use the provided context to answer the user's question.";
|
|
2786
2808
|
const system = buildSystemContent(basePrompt, context);
|
|
2787
2809
|
const response = yield new __await(this.http.post("/api/chat", {
|
|
2788
2810
|
model: this.llmConfig.model,
|
|
@@ -2811,7 +2833,7 @@ var OllamaProvider = class {
|
|
|
2811
2833
|
if (!line.trim()) continue;
|
|
2812
2834
|
try {
|
|
2813
2835
|
const json = JSON.parse(line);
|
|
2814
|
-
if ((
|
|
2836
|
+
if ((_g2 = json.message) == null ? void 0 : _g2.content) {
|
|
2815
2837
|
yield json.message.content;
|
|
2816
2838
|
}
|
|
2817
2839
|
if (json.done) return;
|
|
@@ -2840,10 +2862,10 @@ var OllamaProvider = class {
|
|
|
2840
2862
|
});
|
|
2841
2863
|
}
|
|
2842
2864
|
async embed(text, options) {
|
|
2843
|
-
var
|
|
2844
|
-
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (
|
|
2865
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k;
|
|
2866
|
+
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "nomic-embed-text";
|
|
2845
2867
|
const baseURL = (_f = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.baseUrl) != null ? _e : this.llmConfig.baseUrl) != null ? _f : "http://localhost:11434";
|
|
2846
|
-
const client = baseURL !== ((
|
|
2868
|
+
const client = baseURL !== ((_g2 = this.llmConfig.baseUrl) != null ? _g2 : "http://localhost:11434") ? axios.create({ baseURL, timeout: 6e4 }) : this.http;
|
|
2847
2869
|
let prompt = text;
|
|
2848
2870
|
const queryPrefix = (_i = (_h = this.embeddingConfig) == null ? void 0 : _h.queryPrefix) != null ? _i : model.includes("nomic") ? "search_query: " : "";
|
|
2849
2871
|
const docPrefix = (_k = (_j = this.embeddingConfig) == null ? void 0 : _j.documentPrefix) != null ? _k : model.includes("nomic") ? "search_document: " : "";
|
|
@@ -2942,9 +2964,9 @@ var GeminiProvider = class {
|
|
|
2942
2964
|
static getHealthChecker() {
|
|
2943
2965
|
return {
|
|
2944
2966
|
async check(config) {
|
|
2945
|
-
var
|
|
2967
|
+
var _a2, _b;
|
|
2946
2968
|
const timestamp = Date.now();
|
|
2947
|
-
const apiKey = (_b = (
|
|
2969
|
+
const apiKey = (_b = (_a2 = config.apiKey) != null ? _a2 : process.env.GOOGLE_GENAI_API_KEY) != null ? _b : "";
|
|
2948
2970
|
const modelName = sanitizeModel(config.model);
|
|
2949
2971
|
try {
|
|
2950
2972
|
const { GoogleGenerativeAI: GoogleGenerativeAI2 } = await import("@google/generative-ai");
|
|
@@ -2974,16 +2996,16 @@ var GeminiProvider = class {
|
|
|
2974
2996
|
/** Resolve the embedding client — uses a separate client when the embedding
|
|
2975
2997
|
* API key differs from the LLM API key. */
|
|
2976
2998
|
get embeddingClient() {
|
|
2977
|
-
var
|
|
2978
|
-
if (((
|
|
2999
|
+
var _a2;
|
|
3000
|
+
if (((_a2 = this.embeddingConfig) == null ? void 0 : _a2.apiKey) && this.embeddingConfig.apiKey !== this.llmConfig.apiKey) {
|
|
2979
3001
|
return buildClient(this.embeddingConfig.apiKey);
|
|
2980
3002
|
}
|
|
2981
3003
|
return this.client;
|
|
2982
3004
|
}
|
|
2983
3005
|
/** Resolve the embedding model to use, in order of specificity. */
|
|
2984
3006
|
resolveEmbeddingModel(optionsModel) {
|
|
2985
|
-
var
|
|
2986
|
-
return sanitizeModel((_b = optionsModel != null ? optionsModel : (
|
|
3007
|
+
var _a2, _b;
|
|
3008
|
+
return sanitizeModel((_b = optionsModel != null ? optionsModel : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _b : DEFAULT_EMBEDDING_MODEL);
|
|
2987
3009
|
}
|
|
2988
3010
|
/**
|
|
2989
3011
|
* Convert ChatMessage[] to the Gemini contents format.
|
|
@@ -3003,8 +3025,8 @@ var GeminiProvider = class {
|
|
|
3003
3025
|
// ILLMProvider — chat
|
|
3004
3026
|
// -------------------------------------------------------------------------
|
|
3005
3027
|
async chat(messages, context, options) {
|
|
3006
|
-
var
|
|
3007
|
-
const basePrompt = (_b = (
|
|
3028
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3029
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3008
3030
|
const model = this.client.getGenerativeModel({
|
|
3009
3031
|
model: this.llmConfig.model,
|
|
3010
3032
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3021,8 +3043,8 @@ var GeminiProvider = class {
|
|
|
3021
3043
|
}
|
|
3022
3044
|
chatStream(messages, context, options) {
|
|
3023
3045
|
return __asyncGenerator(this, null, function* () {
|
|
3024
|
-
var
|
|
3025
|
-
const basePrompt = (_b = (
|
|
3046
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3047
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3026
3048
|
const model = this.client.getGenerativeModel({
|
|
3027
3049
|
model: this.llmConfig.model,
|
|
3028
3050
|
systemInstruction: buildSystemContent(basePrompt, context)
|
|
@@ -3057,11 +3079,11 @@ var GeminiProvider = class {
|
|
|
3057
3079
|
// ILLMProvider — embeddings
|
|
3058
3080
|
// -------------------------------------------------------------------------
|
|
3059
3081
|
async embed(text, options) {
|
|
3060
|
-
var
|
|
3082
|
+
var _a2, _b;
|
|
3061
3083
|
const content = applyPrefix(
|
|
3062
3084
|
text,
|
|
3063
3085
|
options == null ? void 0 : options.taskType,
|
|
3064
|
-
(
|
|
3086
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3065
3087
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3066
3088
|
);
|
|
3067
3089
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
@@ -3078,7 +3100,7 @@ var GeminiProvider = class {
|
|
|
3078
3100
|
const modelName = this.resolveEmbeddingModel(options == null ? void 0 : options.model);
|
|
3079
3101
|
const model = this.embeddingClient.getGenerativeModel({ model: modelName });
|
|
3080
3102
|
const requests = texts.map((text) => {
|
|
3081
|
-
var
|
|
3103
|
+
var _a2, _b;
|
|
3082
3104
|
return {
|
|
3083
3105
|
content: {
|
|
3084
3106
|
role: "user",
|
|
@@ -3086,7 +3108,7 @@ var GeminiProvider = class {
|
|
|
3086
3108
|
text: applyPrefix(
|
|
3087
3109
|
text,
|
|
3088
3110
|
options == null ? void 0 : options.taskType,
|
|
3089
|
-
(
|
|
3111
|
+
(_a2 = this.embeddingConfig) == null ? void 0 : _a2.queryPrefix,
|
|
3090
3112
|
(_b = this.embeddingConfig) == null ? void 0 : _b.documentPrefix
|
|
3091
3113
|
)
|
|
3092
3114
|
}]
|
|
@@ -3103,8 +3125,8 @@ var GeminiProvider = class {
|
|
|
3103
3125
|
throw err;
|
|
3104
3126
|
});
|
|
3105
3127
|
return response.embeddings.map((e) => {
|
|
3106
|
-
var
|
|
3107
|
-
return (
|
|
3128
|
+
var _a2;
|
|
3129
|
+
return (_a2 = e.values) != null ? _a2 : [];
|
|
3108
3130
|
});
|
|
3109
3131
|
}
|
|
3110
3132
|
// -------------------------------------------------------------------------
|
|
@@ -3124,192 +3146,511 @@ var GeminiProvider = class {
|
|
|
3124
3146
|
}
|
|
3125
3147
|
};
|
|
3126
3148
|
|
|
3127
|
-
// src/llm/providers/
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3138
|
-
};
|
|
3139
|
-
var LLM_PROFILES = {
|
|
3140
|
-
"openai-compatible": OPENAI_BASE,
|
|
3141
|
-
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3142
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3143
|
-
}),
|
|
3144
|
-
"anthropic-claude": {
|
|
3145
|
-
chatPath: "/v1/messages",
|
|
3146
|
-
responseExtractPath: "content[0].text",
|
|
3147
|
-
headers: { "anthropic-version": "2023-06-01" },
|
|
3148
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3149
|
-
},
|
|
3150
|
-
"google-gemini": {
|
|
3151
|
-
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3152
|
-
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3153
|
-
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3154
|
-
},
|
|
3155
|
-
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3156
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3157
|
-
}),
|
|
3158
|
-
"ollama-standard": {
|
|
3159
|
-
chatPath: "/api/chat",
|
|
3160
|
-
embedPath: "/api/embeddings",
|
|
3161
|
-
responseExtractPath: "message.content",
|
|
3162
|
-
embedExtractPath: "embedding",
|
|
3163
|
-
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3164
|
-
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3165
|
-
}
|
|
3166
|
-
};
|
|
3167
|
-
|
|
3168
|
-
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3169
|
-
var UniversalLLMAdapter = class {
|
|
3170
|
-
constructor(config) {
|
|
3171
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
3172
|
-
this.model = config.model;
|
|
3173
|
-
const llmConfig = config;
|
|
3174
|
-
const options = (_a = llmConfig.options) != null ? _a : {};
|
|
3175
|
-
let profile = {};
|
|
3176
|
-
if (typeof options.profile === "string") {
|
|
3177
|
-
profile = LLM_PROFILES[options.profile] || {};
|
|
3178
|
-
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3179
|
-
profile = options.profile;
|
|
3180
|
-
}
|
|
3181
|
-
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3182
|
-
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3183
|
-
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3184
|
-
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3185
|
-
this.apiKey = config.apiKey;
|
|
3186
|
-
this.baseUrl = (_g = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g : "";
|
|
3187
|
-
if (!this.baseUrl) {
|
|
3188
|
-
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3189
|
-
}
|
|
3190
|
-
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3191
|
-
"Content-Type": "application/json"
|
|
3192
|
-
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3193
|
-
this.http = axios2.create({
|
|
3194
|
-
baseURL: this.baseUrl,
|
|
3195
|
-
headers: this.resolvedHeaders,
|
|
3196
|
-
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3149
|
+
// src/llm/providers/GroqProvider.ts
|
|
3150
|
+
import OpenAI2 from "openai";
|
|
3151
|
+
var GroqProvider = class {
|
|
3152
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3153
|
+
void embeddingConfig;
|
|
3154
|
+
const apiKey = llmConfig.apiKey || process.env.GROQ_API_KEY;
|
|
3155
|
+
if (!apiKey) throw new Error("[GroqProvider] llmConfig.apiKey or GROQ_API_KEY environment variable is required");
|
|
3156
|
+
this.client = new OpenAI2({
|
|
3157
|
+
apiKey,
|
|
3158
|
+
baseURL: llmConfig.baseUrl || "https://api.groq.com/openai/v1"
|
|
3197
3159
|
});
|
|
3160
|
+
this.llmConfig = llmConfig;
|
|
3198
3161
|
}
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3162
|
+
static getValidator() {
|
|
3163
|
+
return {
|
|
3164
|
+
validate(config) {
|
|
3165
|
+
const errors = [];
|
|
3166
|
+
if (!config.apiKey && !process.env.GROQ_API_KEY) {
|
|
3167
|
+
errors.push({
|
|
3168
|
+
field: "llm.apiKey",
|
|
3169
|
+
message: "Groq API key is required",
|
|
3170
|
+
suggestion: "Set GROQ_API_KEY environment variable",
|
|
3171
|
+
severity: "error"
|
|
3172
|
+
});
|
|
3173
|
+
}
|
|
3174
|
+
if (!config.model) {
|
|
3175
|
+
errors.push({
|
|
3176
|
+
field: "llm.model",
|
|
3177
|
+
message: "Groq model name is required",
|
|
3178
|
+
suggestion: 'e.g., "llama-3.3-70b-versatile"',
|
|
3179
|
+
severity: "error"
|
|
3180
|
+
});
|
|
3181
|
+
}
|
|
3182
|
+
return errors;
|
|
3183
|
+
}
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
static getHealthChecker() {
|
|
3187
|
+
return {
|
|
3188
|
+
async check(config) {
|
|
3189
|
+
const timestamp = Date.now();
|
|
3190
|
+
const apiKey = config.apiKey || process.env.GROQ_API_KEY || "";
|
|
3191
|
+
const modelName = config.model;
|
|
3192
|
+
try {
|
|
3193
|
+
const OpenAI4 = await import("openai");
|
|
3194
|
+
const client = new OpenAI4.default({
|
|
3195
|
+
apiKey,
|
|
3196
|
+
baseURL: config.baseUrl || "https://api.groq.com/openai/v1"
|
|
3197
|
+
});
|
|
3198
|
+
const models = await client.models.list();
|
|
3199
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3200
|
+
return {
|
|
3201
|
+
healthy: true,
|
|
3202
|
+
provider: "groq",
|
|
3203
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3204
|
+
timestamp
|
|
3205
|
+
};
|
|
3206
|
+
} catch (error) {
|
|
3207
|
+
return {
|
|
3208
|
+
healthy: false,
|
|
3209
|
+
provider: "groq",
|
|
3210
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3211
|
+
timestamp
|
|
3212
|
+
};
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
};
|
|
3216
|
+
}
|
|
3217
|
+
async chat(messages, context, options) {
|
|
3218
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3219
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3220
|
+
const systemMessage = {
|
|
3221
|
+
role: "system",
|
|
3222
|
+
content: buildSystemContent(basePrompt, context)
|
|
3223
|
+
};
|
|
3202
3224
|
const formattedMessages = [
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3225
|
+
systemMessage,
|
|
3226
|
+
...messages.map((m) => ({
|
|
3227
|
+
role: m.role,
|
|
3228
|
+
content: m.content
|
|
3229
|
+
}))
|
|
3208
3230
|
];
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
} else {
|
|
3218
|
-
payload = {
|
|
3219
|
-
model: this.model,
|
|
3220
|
-
messages: formattedMessages,
|
|
3221
|
-
max_tokens: this.maxTokens,
|
|
3222
|
-
temperature: this.temperature
|
|
3223
|
-
};
|
|
3224
|
-
}
|
|
3225
|
-
const { data } = await this.http.post(path, payload);
|
|
3226
|
-
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3227
|
-
const result = resolvePath(data, extractPath);
|
|
3228
|
-
if (result === void 0) {
|
|
3229
|
-
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3230
|
-
}
|
|
3231
|
-
return String(result);
|
|
3231
|
+
const completion = await this.client.chat.completions.create({
|
|
3232
|
+
model: this.llmConfig.model,
|
|
3233
|
+
messages: formattedMessages,
|
|
3234
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3235
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3236
|
+
stop: options == null ? void 0 : options.stop
|
|
3237
|
+
});
|
|
3238
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3232
3239
|
}
|
|
3233
|
-
|
|
3234
|
-
* Streaming chat using native fetch + ReadableStream.
|
|
3235
|
-
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3236
|
-
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3237
|
-
*/
|
|
3238
|
-
chatStream(messages, context) {
|
|
3240
|
+
chatStream(messages, context, options) {
|
|
3239
3241
|
return __asyncGenerator(this, null, function* () {
|
|
3240
|
-
var
|
|
3241
|
-
const
|
|
3242
|
-
const
|
|
3243
|
-
|
|
3242
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3243
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3244
|
+
const systemMessage = {
|
|
3245
|
+
role: "system",
|
|
3246
|
+
content: buildSystemContent(basePrompt, context)
|
|
3247
|
+
};
|
|
3244
3248
|
const formattedMessages = [
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3249
|
+
systemMessage,
|
|
3250
|
+
...messages.map((m) => ({
|
|
3251
|
+
role: m.role,
|
|
3252
|
+
content: m.content
|
|
3253
|
+
}))
|
|
3250
3254
|
];
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
});
|
|
3259
|
-
if (typeof payload === "object" && payload !== null) {
|
|
3260
|
-
payload.stream = true;
|
|
3261
|
-
}
|
|
3262
|
-
} else {
|
|
3263
|
-
payload = {
|
|
3264
|
-
model: this.model,
|
|
3265
|
-
messages: formattedMessages,
|
|
3266
|
-
max_tokens: this.maxTokens,
|
|
3267
|
-
temperature: this.temperature,
|
|
3268
|
-
stream: true
|
|
3269
|
-
};
|
|
3270
|
-
}
|
|
3271
|
-
const response = yield new __await(fetch(url, {
|
|
3272
|
-
method: "POST",
|
|
3273
|
-
headers: this.resolvedHeaders,
|
|
3274
|
-
body: JSON.stringify(payload)
|
|
3255
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3256
|
+
model: this.llmConfig.model,
|
|
3257
|
+
messages: formattedMessages,
|
|
3258
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3259
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3260
|
+
stop: options == null ? void 0 : options.stop,
|
|
3261
|
+
stream: true
|
|
3275
3262
|
}));
|
|
3276
|
-
if (!
|
|
3277
|
-
|
|
3278
|
-
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3279
|
-
}
|
|
3280
|
-
if (!response.body) {
|
|
3281
|
-
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3263
|
+
if (!stream) {
|
|
3264
|
+
throw new Error("[GroqProvider] completions.create stream is undefined");
|
|
3282
3265
|
}
|
|
3283
|
-
const reader = response.body.getReader();
|
|
3284
|
-
const decoder = new TextDecoder("utf-8");
|
|
3285
|
-
let buffer = "";
|
|
3286
3266
|
try {
|
|
3287
|
-
|
|
3288
|
-
const
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3267
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3268
|
+
const chunk = temp.value;
|
|
3269
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3270
|
+
if (content) yield content;
|
|
3271
|
+
}
|
|
3272
|
+
} catch (temp) {
|
|
3273
|
+
error = [temp];
|
|
3274
|
+
} finally {
|
|
3275
|
+
try {
|
|
3276
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3277
|
+
} finally {
|
|
3278
|
+
if (error)
|
|
3279
|
+
throw error[0];
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
});
|
|
3283
|
+
}
|
|
3284
|
+
async embed(text, options) {
|
|
3285
|
+
void text;
|
|
3286
|
+
void options;
|
|
3287
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3288
|
+
}
|
|
3289
|
+
async batchEmbed(texts, options) {
|
|
3290
|
+
void texts;
|
|
3291
|
+
void options;
|
|
3292
|
+
throw new Error('[GroqProvider] Groq does not provide a native embedding API. Please configure "openai" or "gemini" for embeddings in RagConfig.');
|
|
3293
|
+
}
|
|
3294
|
+
async ping() {
|
|
3295
|
+
try {
|
|
3296
|
+
await this.client.models.list();
|
|
3297
|
+
return true;
|
|
3298
|
+
} catch (err) {
|
|
3299
|
+
console.error("[GroqProvider] Ping failed:", err);
|
|
3300
|
+
return false;
|
|
3301
|
+
}
|
|
3302
|
+
}
|
|
3303
|
+
};
|
|
3304
|
+
|
|
3305
|
+
// src/llm/providers/QwenProvider.ts
|
|
3306
|
+
import OpenAI3 from "openai";
|
|
3307
|
+
var QwenProvider = class {
|
|
3308
|
+
constructor(llmConfig, embeddingConfig) {
|
|
3309
|
+
const apiKey = llmConfig.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY;
|
|
3310
|
+
if (!apiKey) throw new Error("[QwenProvider] llmConfig.apiKey, DASHSCOPE_API_KEY, or QWEN_API_KEY environment variable is required");
|
|
3311
|
+
this.client = new OpenAI3({
|
|
3312
|
+
apiKey,
|
|
3313
|
+
baseURL: llmConfig.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3314
|
+
});
|
|
3315
|
+
this.llmConfig = llmConfig;
|
|
3316
|
+
this.embeddingConfig = embeddingConfig;
|
|
3317
|
+
}
|
|
3318
|
+
static getValidator() {
|
|
3319
|
+
return {
|
|
3320
|
+
validate(config) {
|
|
3321
|
+
const errors = [];
|
|
3322
|
+
const isEmbedding = config.provider === "qwen" && "dimensions" in config;
|
|
3323
|
+
const prefix = isEmbedding ? "embedding" : "llm";
|
|
3324
|
+
if (!config.apiKey && !process.env.DASHSCOPE_API_KEY && !process.env.QWEN_API_KEY) {
|
|
3325
|
+
errors.push({
|
|
3326
|
+
field: `${prefix}.apiKey`,
|
|
3327
|
+
message: "Qwen API key is required",
|
|
3328
|
+
suggestion: "Set DASHSCOPE_API_KEY or QWEN_API_KEY environment variable",
|
|
3329
|
+
severity: "error"
|
|
3330
|
+
});
|
|
3331
|
+
}
|
|
3332
|
+
if (!config.model) {
|
|
3333
|
+
errors.push({
|
|
3334
|
+
field: `${prefix}.model`,
|
|
3335
|
+
message: "Qwen model name is required",
|
|
3336
|
+
suggestion: isEmbedding ? 'e.g., "text-embedding-v3"' : 'e.g., "qwen-plus" or "qwen-max"',
|
|
3337
|
+
severity: "error"
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
return errors;
|
|
3341
|
+
}
|
|
3342
|
+
};
|
|
3343
|
+
}
|
|
3344
|
+
static getHealthChecker() {
|
|
3345
|
+
return {
|
|
3346
|
+
async check(config) {
|
|
3347
|
+
const timestamp = Date.now();
|
|
3348
|
+
const apiKey = config.apiKey || process.env.DASHSCOPE_API_KEY || process.env.QWEN_API_KEY || "";
|
|
3349
|
+
const modelName = config.model;
|
|
3350
|
+
try {
|
|
3351
|
+
const OpenAI4 = await import("openai");
|
|
3352
|
+
const client = new OpenAI4.default({
|
|
3353
|
+
apiKey,
|
|
3354
|
+
baseURL: config.baseUrl || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3355
|
+
});
|
|
3356
|
+
const models = await client.models.list();
|
|
3357
|
+
const hasModel = models.data.some((m) => m.id === modelName);
|
|
3358
|
+
return {
|
|
3359
|
+
healthy: true,
|
|
3360
|
+
provider: "qwen",
|
|
3361
|
+
capabilities: { model: modelName, available: hasModel, totalModels: models.data.length },
|
|
3362
|
+
timestamp
|
|
3363
|
+
};
|
|
3364
|
+
} catch (error) {
|
|
3365
|
+
return {
|
|
3366
|
+
healthy: false,
|
|
3367
|
+
provider: "qwen",
|
|
3368
|
+
error: `Connection failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
3369
|
+
timestamp
|
|
3370
|
+
};
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
async chat(messages, context, options) {
|
|
3376
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i;
|
|
3377
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3378
|
+
const systemMessage = {
|
|
3379
|
+
role: "system",
|
|
3380
|
+
content: buildSystemContent(basePrompt, context)
|
|
3381
|
+
};
|
|
3382
|
+
const formattedMessages = [
|
|
3383
|
+
systemMessage,
|
|
3384
|
+
...messages.map((m) => ({
|
|
3385
|
+
role: m.role,
|
|
3386
|
+
content: m.content
|
|
3387
|
+
}))
|
|
3388
|
+
];
|
|
3389
|
+
const completion = await this.client.chat.completions.create({
|
|
3390
|
+
model: this.llmConfig.model,
|
|
3391
|
+
messages: formattedMessages,
|
|
3392
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3393
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3394
|
+
stop: options == null ? void 0 : options.stop
|
|
3395
|
+
});
|
|
3396
|
+
return (_i = (_h = (_g2 = completion.choices[0]) == null ? void 0 : _g2.message) == null ? void 0 : _h.content) != null ? _i : "";
|
|
3397
|
+
}
|
|
3398
|
+
chatStream(messages, context, options) {
|
|
3399
|
+
return __asyncGenerator(this, null, function* () {
|
|
3400
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3401
|
+
const basePrompt = (_b = (_a2 = options == null ? void 0 : options.systemPrompt) != null ? _a2 : this.llmConfig.systemPrompt) != null ? _b : "You are a helpful assistant. Answer questions based on the provided context.";
|
|
3402
|
+
const systemMessage = {
|
|
3403
|
+
role: "system",
|
|
3404
|
+
content: buildSystemContent(basePrompt, context)
|
|
3405
|
+
};
|
|
3406
|
+
const formattedMessages = [
|
|
3407
|
+
systemMessage,
|
|
3408
|
+
...messages.map((m) => ({
|
|
3409
|
+
role: m.role,
|
|
3410
|
+
content: m.content
|
|
3411
|
+
}))
|
|
3412
|
+
];
|
|
3413
|
+
const stream = yield new __await(this.client.chat.completions.create({
|
|
3414
|
+
model: this.llmConfig.model,
|
|
3415
|
+
messages: formattedMessages,
|
|
3416
|
+
max_tokens: (_d = (_c = options == null ? void 0 : options.maxTokens) != null ? _c : this.llmConfig.maxTokens) != null ? _d : 1024,
|
|
3417
|
+
temperature: (_f = (_e = options == null ? void 0 : options.temperature) != null ? _e : this.llmConfig.temperature) != null ? _f : 0.7,
|
|
3418
|
+
stop: options == null ? void 0 : options.stop,
|
|
3419
|
+
stream: true
|
|
3420
|
+
}));
|
|
3421
|
+
if (!stream) {
|
|
3422
|
+
throw new Error("[QwenProvider] completions.create stream is undefined");
|
|
3423
|
+
}
|
|
3424
|
+
try {
|
|
3425
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
3426
|
+
const chunk = temp.value;
|
|
3427
|
+
const content = ((_h = (_g2 = chunk.choices[0]) == null ? void 0 : _g2.delta) == null ? void 0 : _h.content) || "";
|
|
3428
|
+
if (content) yield content;
|
|
3429
|
+
}
|
|
3430
|
+
} catch (temp) {
|
|
3431
|
+
error = [temp];
|
|
3432
|
+
} finally {
|
|
3433
|
+
try {
|
|
3434
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
3435
|
+
} finally {
|
|
3436
|
+
if (error)
|
|
3437
|
+
throw error[0];
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
});
|
|
3441
|
+
}
|
|
3442
|
+
async embed(text, options) {
|
|
3443
|
+
const results = await this.batchEmbed([text], options);
|
|
3444
|
+
return results[0];
|
|
3445
|
+
}
|
|
3446
|
+
async batchEmbed(texts, options) {
|
|
3447
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
3448
|
+
const model = (_c = (_b = options == null ? void 0 : options.model) != null ? _b : (_a2 = this.embeddingConfig) == null ? void 0 : _a2.model) != null ? _c : "text-embedding-v1";
|
|
3449
|
+
const apiKey = (_e = (_d = this.embeddingConfig) == null ? void 0 : _d.apiKey) != null ? _e : this.llmConfig.apiKey;
|
|
3450
|
+
const client = apiKey !== this.llmConfig.apiKey ? new OpenAI3({
|
|
3451
|
+
apiKey,
|
|
3452
|
+
baseURL: ((_f = this.embeddingConfig) == null ? void 0 : _f.baseUrl) || "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
|
3453
|
+
}) : this.client;
|
|
3454
|
+
const response = await client.embeddings.create({ model, input: texts });
|
|
3455
|
+
return response.data.map((d) => d.embedding);
|
|
3456
|
+
}
|
|
3457
|
+
async ping() {
|
|
3458
|
+
try {
|
|
3459
|
+
await this.client.models.list();
|
|
3460
|
+
return true;
|
|
3461
|
+
} catch (err) {
|
|
3462
|
+
console.error("[QwenProvider] Ping failed:", err);
|
|
3463
|
+
return false;
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
};
|
|
3467
|
+
|
|
3468
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3469
|
+
init_templateUtils();
|
|
3470
|
+
import axios2 from "axios";
|
|
3471
|
+
|
|
3472
|
+
// src/config/UniversalProfiles.ts
|
|
3473
|
+
var OPENAI_BASE = {
|
|
3474
|
+
chatPath: "/chat/completions",
|
|
3475
|
+
embedPath: "/embeddings",
|
|
3476
|
+
responseExtractPath: "choices[0].message.content",
|
|
3477
|
+
embedExtractPath: "data[0].embedding",
|
|
3478
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}}}'
|
|
3479
|
+
};
|
|
3480
|
+
var LLM_PROFILES = {
|
|
3481
|
+
"openai-compatible": OPENAI_BASE,
|
|
3482
|
+
"litellm": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3483
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}},"temperature":{{temperature}},"stream":false}'
|
|
3484
|
+
}),
|
|
3485
|
+
"anthropic-claude": {
|
|
3486
|
+
chatPath: "/v1/messages",
|
|
3487
|
+
responseExtractPath: "content[0].text",
|
|
3488
|
+
headers: { "anthropic-version": "2023-06-01" },
|
|
3489
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"max_tokens":{{maxTokens}}}'
|
|
3490
|
+
},
|
|
3491
|
+
"google-gemini": {
|
|
3492
|
+
chatPath: "/v1beta/models/{{model}}:generateContent",
|
|
3493
|
+
responseExtractPath: "candidates[0].content.parts[0].text",
|
|
3494
|
+
chatPayloadTemplate: '{"contents":[{"parts":[{"text":"{{messages}}"}]}]}'
|
|
3495
|
+
},
|
|
3496
|
+
"github-copilot": __spreadProps(__spreadValues({}, OPENAI_BASE), {
|
|
3497
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"temperature":{{temperature}}}'
|
|
3498
|
+
}),
|
|
3499
|
+
"ollama-standard": {
|
|
3500
|
+
chatPath: "/api/chat",
|
|
3501
|
+
embedPath: "/api/embeddings",
|
|
3502
|
+
responseExtractPath: "message.content",
|
|
3503
|
+
embedExtractPath: "embedding",
|
|
3504
|
+
chatPayloadTemplate: '{"model":"{{model}}","messages":{{messages}},"stream":false}',
|
|
3505
|
+
embedPayloadTemplate: '{"model":"{{model}}","prompt":"{{input}}"}'
|
|
3506
|
+
}
|
|
3507
|
+
};
|
|
3508
|
+
|
|
3509
|
+
// src/llm/providers/UniversalLLMAdapter.ts
|
|
3510
|
+
var UniversalLLMAdapter = class {
|
|
3511
|
+
constructor(config) {
|
|
3512
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h;
|
|
3513
|
+
this.model = config.model;
|
|
3514
|
+
const llmConfig = config;
|
|
3515
|
+
const options = (_a2 = llmConfig.options) != null ? _a2 : {};
|
|
3516
|
+
let profile = {};
|
|
3517
|
+
if (typeof options.profile === "string") {
|
|
3518
|
+
profile = LLM_PROFILES[options.profile] || {};
|
|
3519
|
+
} else if (typeof options.profile === "object" && options.profile !== null) {
|
|
3520
|
+
profile = options.profile;
|
|
3521
|
+
}
|
|
3522
|
+
this.opts = __spreadValues(__spreadValues({}, profile), (_b = llmConfig.options) != null ? _b : {});
|
|
3523
|
+
this.systemPrompt = (_c = llmConfig.systemPrompt) != null ? _c : "You are a helpful AI assistant. Use the provided context to answer the user.";
|
|
3524
|
+
this.maxTokens = (_d = llmConfig.maxTokens) != null ? _d : 1024;
|
|
3525
|
+
this.temperature = (_e = llmConfig.temperature) != null ? _e : 0;
|
|
3526
|
+
this.apiKey = config.apiKey;
|
|
3527
|
+
this.baseUrl = (_g2 = (_f = llmConfig.baseUrl) != null ? _f : this.opts.baseUrl) != null ? _g2 : "";
|
|
3528
|
+
if (!this.baseUrl) {
|
|
3529
|
+
throw new Error("[UniversalLLMAdapter] baseUrl is required in config or config.options");
|
|
3530
|
+
}
|
|
3531
|
+
this.resolvedHeaders = __spreadValues(__spreadValues({
|
|
3532
|
+
"Content-Type": "application/json"
|
|
3533
|
+
}, config.apiKey ? { Authorization: `Bearer ${config.apiKey}` } : {}), this.opts.headers || {});
|
|
3534
|
+
this.http = axios2.create({
|
|
3535
|
+
baseURL: this.baseUrl,
|
|
3536
|
+
headers: this.resolvedHeaders,
|
|
3537
|
+
timeout: (_h = this.opts.timeout) != null ? _h : 6e4
|
|
3538
|
+
});
|
|
3539
|
+
}
|
|
3540
|
+
async chat(messages, context) {
|
|
3541
|
+
var _a2, _b;
|
|
3542
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3543
|
+
const formattedMessages = [
|
|
3544
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3545
|
+
|
|
3546
|
+
Context:
|
|
3547
|
+
${context != null ? context : "None"}` },
|
|
3548
|
+
...messages
|
|
3549
|
+
];
|
|
3550
|
+
let payload;
|
|
3551
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3552
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3553
|
+
model: this.model,
|
|
3554
|
+
messages: formattedMessages,
|
|
3555
|
+
maxTokens: this.maxTokens,
|
|
3556
|
+
temperature: this.temperature
|
|
3557
|
+
});
|
|
3558
|
+
} else {
|
|
3559
|
+
payload = {
|
|
3560
|
+
model: this.model,
|
|
3561
|
+
messages: formattedMessages,
|
|
3562
|
+
max_tokens: this.maxTokens,
|
|
3563
|
+
temperature: this.temperature
|
|
3564
|
+
};
|
|
3565
|
+
}
|
|
3566
|
+
const { data } = await this.http.post(path2, payload);
|
|
3567
|
+
const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
3568
|
+
const result = resolvePath(data, extractPath);
|
|
3569
|
+
if (result === void 0) {
|
|
3570
|
+
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
3571
|
+
}
|
|
3572
|
+
return String(result);
|
|
3573
|
+
}
|
|
3574
|
+
/**
|
|
3575
|
+
* Streaming chat using native fetch + ReadableStream.
|
|
3576
|
+
* Parses OpenAI-compatible SSE frames: `data: {...}\n\n`
|
|
3577
|
+
* Works with vLLM, LMStudio, Together AI, Fireworks, and any OpenAI-compatible API.
|
|
3578
|
+
*/
|
|
3579
|
+
chatStream(messages, context) {
|
|
3580
|
+
return __asyncGenerator(this, null, function* () {
|
|
3581
|
+
var _a2, _b, _c;
|
|
3582
|
+
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
3583
|
+
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
3584
|
+
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
3585
|
+
const formattedMessages = [
|
|
3586
|
+
{ role: "system", content: `${this.systemPrompt}
|
|
3587
|
+
|
|
3588
|
+
Context:
|
|
3589
|
+
${context != null ? context : "None"}` },
|
|
3590
|
+
...messages
|
|
3591
|
+
];
|
|
3592
|
+
let payload;
|
|
3593
|
+
if (this.opts.chatPayloadTemplate) {
|
|
3594
|
+
payload = buildPayload(this.opts.chatPayloadTemplate, {
|
|
3595
|
+
model: this.model,
|
|
3596
|
+
messages: formattedMessages,
|
|
3597
|
+
maxTokens: this.maxTokens,
|
|
3598
|
+
temperature: this.temperature
|
|
3599
|
+
});
|
|
3600
|
+
if (typeof payload === "object" && payload !== null) {
|
|
3601
|
+
payload.stream = true;
|
|
3602
|
+
}
|
|
3603
|
+
} else {
|
|
3604
|
+
payload = {
|
|
3605
|
+
model: this.model,
|
|
3606
|
+
messages: formattedMessages,
|
|
3607
|
+
max_tokens: this.maxTokens,
|
|
3608
|
+
temperature: this.temperature,
|
|
3609
|
+
stream: true
|
|
3610
|
+
};
|
|
3611
|
+
}
|
|
3612
|
+
const response = yield new __await(fetch(url, {
|
|
3613
|
+
method: "POST",
|
|
3614
|
+
headers: this.resolvedHeaders,
|
|
3615
|
+
body: JSON.stringify(payload)
|
|
3616
|
+
}));
|
|
3617
|
+
if (!response.ok) {
|
|
3618
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
3619
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
3620
|
+
}
|
|
3621
|
+
if (!response.body) {
|
|
3622
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
3623
|
+
}
|
|
3624
|
+
const reader = response.body.getReader();
|
|
3625
|
+
const decoder = new TextDecoder("utf-8");
|
|
3626
|
+
let buffer = "";
|
|
3627
|
+
try {
|
|
3628
|
+
while (true) {
|
|
3629
|
+
const { done, value } = yield new __await(reader.read());
|
|
3630
|
+
if (done) break;
|
|
3631
|
+
buffer += decoder.decode(value, { stream: true });
|
|
3632
|
+
const lines = buffer.split("\n");
|
|
3633
|
+
buffer = (_c = lines.pop()) != null ? _c : "";
|
|
3634
|
+
for (const line of lines) {
|
|
3635
|
+
const trimmed = line.trim();
|
|
3636
|
+
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
3637
|
+
if (!trimmed.startsWith("data:")) continue;
|
|
3638
|
+
try {
|
|
3639
|
+
const json = JSON.parse(trimmed.slice(5).trim());
|
|
3640
|
+
const text = resolvePath(json, extractPath);
|
|
3641
|
+
if (text && typeof text === "string") yield text;
|
|
3642
|
+
} catch (e) {
|
|
3643
|
+
}
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
if (buffer.trim() && buffer.trim() !== "data: [DONE]") {
|
|
3647
|
+
const jsonStr = buffer.replace(/^data:\s*/, "").trim();
|
|
3648
|
+
try {
|
|
3649
|
+
const json = JSON.parse(jsonStr);
|
|
3650
|
+
const text = resolvePath(json, extractPath);
|
|
3651
|
+
if (text && typeof text === "string") yield text;
|
|
3652
|
+
} catch (e) {
|
|
3653
|
+
}
|
|
3313
3654
|
}
|
|
3314
3655
|
} finally {
|
|
3315
3656
|
reader.releaseLock();
|
|
@@ -3317,8 +3658,8 @@ ${context != null ? context : "None"}` },
|
|
|
3317
3658
|
});
|
|
3318
3659
|
}
|
|
3319
3660
|
async embed(text) {
|
|
3320
|
-
var
|
|
3321
|
-
const
|
|
3661
|
+
var _a2, _b;
|
|
3662
|
+
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
3322
3663
|
let payload;
|
|
3323
3664
|
if (this.opts.embedPayloadTemplate) {
|
|
3324
3665
|
payload = buildPayload(this.opts.embedPayloadTemplate, {
|
|
@@ -3331,7 +3672,7 @@ ${context != null ? context : "None"}` },
|
|
|
3331
3672
|
input: text
|
|
3332
3673
|
};
|
|
3333
3674
|
}
|
|
3334
|
-
const { data } = await this.http.post(
|
|
3675
|
+
const { data } = await this.http.post(path2, payload);
|
|
3335
3676
|
const extractPath = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
3336
3677
|
const vector = resolvePath(data, extractPath);
|
|
3337
3678
|
if (!Array.isArray(vector)) {
|
|
@@ -3399,13 +3740,13 @@ var AuthenticationException = class extends RetrivoraError {
|
|
|
3399
3740
|
}
|
|
3400
3741
|
};
|
|
3401
3742
|
function wrapError(err, defaultCode, defaultMessage) {
|
|
3402
|
-
var
|
|
3743
|
+
var _a2;
|
|
3403
3744
|
if (err instanceof RetrivoraError) {
|
|
3404
3745
|
return err;
|
|
3405
3746
|
}
|
|
3406
3747
|
const error = err;
|
|
3407
3748
|
const message = (error == null ? void 0 : error.message) || defaultMessage || String(err);
|
|
3408
|
-
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((
|
|
3749
|
+
const status = (error == null ? void 0 : error.status) || (error == null ? void 0 : error.statusCode) || ((_a2 = error == null ? void 0 : error.response) == null ? void 0 : _a2.status);
|
|
3409
3750
|
const code = error == null ? void 0 : error.code;
|
|
3410
3751
|
if (status === 429 || /rate[- ]?limit/i.test(message) || code === "RATE_LIMIT_EXCEEDED") {
|
|
3411
3752
|
return new RateLimitException(message, err);
|
|
@@ -3469,6 +3810,8 @@ var LLMFactory = class _LLMFactory {
|
|
|
3469
3810
|
"anthropic",
|
|
3470
3811
|
"ollama",
|
|
3471
3812
|
"gemini",
|
|
3813
|
+
"groq",
|
|
3814
|
+
"qwen",
|
|
3472
3815
|
"rest",
|
|
3473
3816
|
"universal_rest",
|
|
3474
3817
|
"custom",
|
|
@@ -3476,7 +3819,7 @@ var LLMFactory = class _LLMFactory {
|
|
|
3476
3819
|
];
|
|
3477
3820
|
}
|
|
3478
3821
|
static create(llmConfig, embeddingConfig) {
|
|
3479
|
-
var
|
|
3822
|
+
var _a2, _b, _c;
|
|
3480
3823
|
switch (llmConfig.provider) {
|
|
3481
3824
|
case "openai":
|
|
3482
3825
|
return new OpenAIProvider(llmConfig, embeddingConfig);
|
|
@@ -3486,12 +3829,16 @@ var LLMFactory = class _LLMFactory {
|
|
|
3486
3829
|
return new OllamaProvider(llmConfig, embeddingConfig);
|
|
3487
3830
|
case "gemini":
|
|
3488
3831
|
return new GeminiProvider(llmConfig, embeddingConfig);
|
|
3832
|
+
case "groq":
|
|
3833
|
+
return new GroqProvider(llmConfig, embeddingConfig);
|
|
3834
|
+
case "qwen":
|
|
3835
|
+
return new QwenProvider(llmConfig, embeddingConfig);
|
|
3489
3836
|
case "rest":
|
|
3490
3837
|
case "universal_rest":
|
|
3491
3838
|
case "custom":
|
|
3492
3839
|
return new UniversalLLMAdapter(llmConfig);
|
|
3493
3840
|
default: {
|
|
3494
|
-
const providerName = String((
|
|
3841
|
+
const providerName = String((_a2 = llmConfig.provider) != null ? _a2 : "").toLowerCase();
|
|
3495
3842
|
const customFactory = customProviders.get(providerName);
|
|
3496
3843
|
if (customFactory) {
|
|
3497
3844
|
return customFactory(llmConfig);
|
|
@@ -3528,6 +3875,10 @@ var LLMFactory = class _LLMFactory {
|
|
|
3528
3875
|
return OllamaProvider;
|
|
3529
3876
|
case "gemini":
|
|
3530
3877
|
return GeminiProvider;
|
|
3878
|
+
case "groq":
|
|
3879
|
+
return GroqProvider;
|
|
3880
|
+
case "qwen":
|
|
3881
|
+
return QwenProvider;
|
|
3531
3882
|
case "rest":
|
|
3532
3883
|
case "universal_rest":
|
|
3533
3884
|
case "custom":
|
|
@@ -3589,7 +3940,7 @@ var ProviderRegistry = class {
|
|
|
3589
3940
|
return null;
|
|
3590
3941
|
}
|
|
3591
3942
|
static async loadVectorProviderClass(provider) {
|
|
3592
|
-
var
|
|
3943
|
+
var _a2;
|
|
3593
3944
|
if (this.vectorProviders[provider]) return this.vectorProviders[provider];
|
|
3594
3945
|
switch (provider) {
|
|
3595
3946
|
case "pinecone": {
|
|
@@ -3598,7 +3949,7 @@ var ProviderRegistry = class {
|
|
|
3598
3949
|
}
|
|
3599
3950
|
case "pgvector":
|
|
3600
3951
|
case "postgresql": {
|
|
3601
|
-
const postgresMode = ((
|
|
3952
|
+
const postgresMode = ((_a2 = process.env.POSTGRES_MODE) != null ? _a2 : "multi").toLowerCase();
|
|
3602
3953
|
if (postgresMode === "single") {
|
|
3603
3954
|
const { PostgreSQLProvider: PostgreSQLProvider2 } = await Promise.resolve().then(() => (init_PostgreSQLProvider(), PostgreSQLProvider_exports));
|
|
3604
3955
|
return PostgreSQLProvider2;
|
|
@@ -4047,11 +4398,11 @@ var LlamaIndexIngestor = class {
|
|
|
4047
4398
|
* than standard character-count splitting.
|
|
4048
4399
|
*/
|
|
4049
4400
|
async chunk(text, options = {}) {
|
|
4050
|
-
var
|
|
4401
|
+
var _a2, _b;
|
|
4051
4402
|
try {
|
|
4052
4403
|
const { Document, SentenceSplitter, MetadataMode } = await import(`${"llamaindex"}`);
|
|
4053
4404
|
const splitter = new SentenceSplitter({
|
|
4054
|
-
chunkSize: (
|
|
4405
|
+
chunkSize: (_a2 = options.chunkSize) != null ? _a2 : 1e3,
|
|
4055
4406
|
chunkOverlap: (_b = options.chunkOverlap) != null ? _b : 200
|
|
4056
4407
|
});
|
|
4057
4408
|
const doc = new Document({ text, metadata: options.metadata || {} });
|
|
@@ -4160,7 +4511,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4160
4511
|
* The agent returns `{ messages: [...] }` — the last message is the final answer.
|
|
4161
4512
|
*/
|
|
4162
4513
|
async run(input, chatHistory = []) {
|
|
4163
|
-
var
|
|
4514
|
+
var _a2, _b, _c;
|
|
4164
4515
|
if (!this.agent) {
|
|
4165
4516
|
throw new Error("[LangChainAgent] Agent not initialized. Call initialize() first.");
|
|
4166
4517
|
}
|
|
@@ -4171,7 +4522,7 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4171
4522
|
const response = await this.agent.invoke({
|
|
4172
4523
|
messages: [...historyMessages, new HumanMessage(input)]
|
|
4173
4524
|
});
|
|
4174
|
-
const lastMessage = (
|
|
4525
|
+
const lastMessage = (_a2 = response == null ? void 0 : response.messages) == null ? void 0 : _a2.at(-1);
|
|
4175
4526
|
if (lastMessage && typeof lastMessage.content === "string") {
|
|
4176
4527
|
return lastMessage.content;
|
|
4177
4528
|
}
|
|
@@ -4182,6 +4533,437 @@ ${error instanceof Error ? error.message : String(error)}`
|
|
|
4182
4533
|
}
|
|
4183
4534
|
};
|
|
4184
4535
|
|
|
4536
|
+
// src/core/mcp.ts
|
|
4537
|
+
import { spawn } from "child_process";
|
|
4538
|
+
var MCPClient = class {
|
|
4539
|
+
constructor(config) {
|
|
4540
|
+
this.config = config;
|
|
4541
|
+
this.messageIdCounter = 0;
|
|
4542
|
+
this.pendingRequests = /* @__PURE__ */ new Map();
|
|
4543
|
+
this.stdioBuffer = "";
|
|
4544
|
+
this.initialized = false;
|
|
4545
|
+
}
|
|
4546
|
+
getNextMessageId() {
|
|
4547
|
+
return ++this.messageIdCounter;
|
|
4548
|
+
}
|
|
4549
|
+
/**
|
|
4550
|
+
* Connect and initialize the MCP server connection.
|
|
4551
|
+
*/
|
|
4552
|
+
async connect() {
|
|
4553
|
+
if (this.initialized) return;
|
|
4554
|
+
if (this.config.transport === "stdio") {
|
|
4555
|
+
await this.connectStdio();
|
|
4556
|
+
} else {
|
|
4557
|
+
await this.connectSSE();
|
|
4558
|
+
}
|
|
4559
|
+
try {
|
|
4560
|
+
const response = await this.sendJsonRpc("initialize", {
|
|
4561
|
+
protocolVersion: "2024-11-05",
|
|
4562
|
+
capabilities: {},
|
|
4563
|
+
clientInfo: {
|
|
4564
|
+
name: "retrivora-sdk",
|
|
4565
|
+
version: "1.0.0"
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
await this.sendNotification("notifications/initialized");
|
|
4569
|
+
this.initialized = true;
|
|
4570
|
+
console.log(`[MCPClient] Connected and initialized server "${this.config.name}" successfully.`);
|
|
4571
|
+
} catch (err) {
|
|
4572
|
+
this.disconnect();
|
|
4573
|
+
throw new Error(`[MCPClient] Failed to initialize server "${this.config.name}": ${err.message}`);
|
|
4574
|
+
}
|
|
4575
|
+
}
|
|
4576
|
+
async connectStdio() {
|
|
4577
|
+
var _a2;
|
|
4578
|
+
const cmd = this.config.command;
|
|
4579
|
+
if (!cmd) {
|
|
4580
|
+
throw new Error(`[MCPClient] Command option is required for stdio transport on "${this.config.name}"`);
|
|
4581
|
+
}
|
|
4582
|
+
const args = this.config.args || [];
|
|
4583
|
+
const env = __spreadValues(__spreadValues({}, process.env), this.config.env || {});
|
|
4584
|
+
this.childProcess = spawn(cmd, args, { env, shell: true });
|
|
4585
|
+
if (!this.childProcess || !this.childProcess.stdout || !this.childProcess.stdin) {
|
|
4586
|
+
throw new Error(`[MCPClient] Failed to spawn stdio child process for "${this.config.name}"`);
|
|
4587
|
+
}
|
|
4588
|
+
this.childProcess.stdout.on("data", (data) => {
|
|
4589
|
+
this.stdioBuffer += data.toString("utf-8");
|
|
4590
|
+
this.processStdioLines();
|
|
4591
|
+
});
|
|
4592
|
+
(_a2 = this.childProcess.stderr) == null ? void 0 : _a2.on("data", (data) => {
|
|
4593
|
+
console.warn(`[MCPClient] [stderr] [${this.config.name}]:`, data.toString("utf-8"));
|
|
4594
|
+
});
|
|
4595
|
+
this.childProcess.on("close", (code) => {
|
|
4596
|
+
console.log(`[MCPClient] Connection closed for "${this.config.name}" with exit code: ${code}`);
|
|
4597
|
+
this.disconnect();
|
|
4598
|
+
});
|
|
4599
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4600
|
+
}
|
|
4601
|
+
processStdioLines() {
|
|
4602
|
+
let newlineIndex;
|
|
4603
|
+
while ((newlineIndex = this.stdioBuffer.indexOf("\n")) !== -1) {
|
|
4604
|
+
const line = this.stdioBuffer.substring(0, newlineIndex).trim();
|
|
4605
|
+
this.stdioBuffer = this.stdioBuffer.substring(newlineIndex + 1);
|
|
4606
|
+
if (!line) continue;
|
|
4607
|
+
try {
|
|
4608
|
+
const payload = JSON.parse(line);
|
|
4609
|
+
if (payload.id !== void 0) {
|
|
4610
|
+
const req = this.pendingRequests.get(Number(payload.id));
|
|
4611
|
+
if (req) {
|
|
4612
|
+
this.pendingRequests.delete(Number(payload.id));
|
|
4613
|
+
if (payload.error) {
|
|
4614
|
+
req.reject(new Error(payload.error.message || JSON.stringify(payload.error)));
|
|
4615
|
+
} else {
|
|
4616
|
+
req.resolve(payload.result);
|
|
4617
|
+
}
|
|
4618
|
+
}
|
|
4619
|
+
}
|
|
4620
|
+
} catch (e) {
|
|
4621
|
+
console.warn(`[MCPClient] Error parsing stdio JSON-RPC line from "${this.config.name}":`, e, "Line content:", line);
|
|
4622
|
+
}
|
|
4623
|
+
}
|
|
4624
|
+
}
|
|
4625
|
+
async connectSSE() {
|
|
4626
|
+
if (!this.config.url) {
|
|
4627
|
+
throw new Error(`[MCPClient] URL is required for sse transport on "${this.config.name}"`);
|
|
4628
|
+
}
|
|
4629
|
+
this.sseUrl = this.config.url;
|
|
4630
|
+
}
|
|
4631
|
+
async sendJsonRpc(method, params) {
|
|
4632
|
+
const id = this.getNextMessageId();
|
|
4633
|
+
const request = {
|
|
4634
|
+
jsonrpc: "2.0",
|
|
4635
|
+
id,
|
|
4636
|
+
method,
|
|
4637
|
+
params
|
|
4638
|
+
};
|
|
4639
|
+
if (this.config.transport === "stdio") {
|
|
4640
|
+
if (!this.childProcess || !this.childProcess.stdin) {
|
|
4641
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" is not connected (stdio process missing)`);
|
|
4642
|
+
}
|
|
4643
|
+
return new Promise((resolve, reject) => {
|
|
4644
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
4645
|
+
this.childProcess.stdin.write(JSON.stringify(request) + "\n", "utf-8");
|
|
4646
|
+
});
|
|
4647
|
+
} else {
|
|
4648
|
+
if (!this.sseUrl) {
|
|
4649
|
+
throw new Error(`[MCPClient] Server "${this.config.name}" SSE URL is not initialized`);
|
|
4650
|
+
}
|
|
4651
|
+
const response = await fetch(this.sseUrl, {
|
|
4652
|
+
method: "POST",
|
|
4653
|
+
headers: { "Content-Type": "application/json" },
|
|
4654
|
+
body: JSON.stringify(request)
|
|
4655
|
+
});
|
|
4656
|
+
if (!response.ok) {
|
|
4657
|
+
throw new Error(`SSE JSON-RPC POST failed with status ${response.status}`);
|
|
4658
|
+
}
|
|
4659
|
+
const payload = await response.json();
|
|
4660
|
+
if (payload.error) {
|
|
4661
|
+
throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
4662
|
+
}
|
|
4663
|
+
return payload.result;
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
async sendNotification(method, params) {
|
|
4667
|
+
var _a2;
|
|
4668
|
+
const notification = {
|
|
4669
|
+
jsonrpc: "2.0",
|
|
4670
|
+
method,
|
|
4671
|
+
params
|
|
4672
|
+
};
|
|
4673
|
+
if (this.config.transport === "stdio") {
|
|
4674
|
+
if ((_a2 = this.childProcess) == null ? void 0 : _a2.stdin) {
|
|
4675
|
+
this.childProcess.stdin.write(JSON.stringify(notification) + "\n", "utf-8");
|
|
4676
|
+
}
|
|
4677
|
+
} else if (this.sseUrl) {
|
|
4678
|
+
await fetch(this.sseUrl, {
|
|
4679
|
+
method: "POST",
|
|
4680
|
+
headers: { "Content-Type": "application/json" },
|
|
4681
|
+
body: JSON.stringify(notification)
|
|
4682
|
+
}).catch((err) => console.warn("[MCPClient] Failed to send notification over SSE:", err));
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
/**
|
|
4686
|
+
* List all tools offered by the MCP server.
|
|
4687
|
+
*/
|
|
4688
|
+
async listTools() {
|
|
4689
|
+
await this.connect();
|
|
4690
|
+
const result = await this.sendJsonRpc("tools/list", {});
|
|
4691
|
+
return (result == null ? void 0 : result.tools) || [];
|
|
4692
|
+
}
|
|
4693
|
+
/**
|
|
4694
|
+
* Execute a tool on the MCP server.
|
|
4695
|
+
*/
|
|
4696
|
+
async callTool(name, args = {}) {
|
|
4697
|
+
await this.connect();
|
|
4698
|
+
return await this.sendJsonRpc("tools/call", { name, arguments: args });
|
|
4699
|
+
}
|
|
4700
|
+
disconnect() {
|
|
4701
|
+
this.initialized = false;
|
|
4702
|
+
this.pendingRequests.forEach((req) => req.reject(new Error("MCPClient disconnected")));
|
|
4703
|
+
this.pendingRequests.clear();
|
|
4704
|
+
if (this.childProcess) {
|
|
4705
|
+
try {
|
|
4706
|
+
this.childProcess.kill();
|
|
4707
|
+
} catch (e) {
|
|
4708
|
+
}
|
|
4709
|
+
this.childProcess = void 0;
|
|
4710
|
+
}
|
|
4711
|
+
}
|
|
4712
|
+
};
|
|
4713
|
+
var MCPRegistry = class {
|
|
4714
|
+
constructor(servers = []) {
|
|
4715
|
+
this.clients = [];
|
|
4716
|
+
this.clients = servers.map((cfg) => new MCPClient(cfg));
|
|
4717
|
+
}
|
|
4718
|
+
async getAllTools() {
|
|
4719
|
+
const list = [];
|
|
4720
|
+
await Promise.all(
|
|
4721
|
+
this.clients.map(async (client) => {
|
|
4722
|
+
try {
|
|
4723
|
+
const tools = await client.listTools();
|
|
4724
|
+
tools.forEach((t) => list.push({ serverName: client["config"].name, tool: t }));
|
|
4725
|
+
} catch (e) {
|
|
4726
|
+
console.warn(`[MCPRegistry] Failed to fetch tools from server "${client["config"].name}":`, e);
|
|
4727
|
+
}
|
|
4728
|
+
})
|
|
4729
|
+
);
|
|
4730
|
+
return list;
|
|
4731
|
+
}
|
|
4732
|
+
async callTool(toolName, args = {}) {
|
|
4733
|
+
for (const client of this.clients) {
|
|
4734
|
+
try {
|
|
4735
|
+
const tools = await client.listTools();
|
|
4736
|
+
if (tools.some((t) => t.name === toolName)) {
|
|
4737
|
+
return await client.callTool(toolName, args);
|
|
4738
|
+
}
|
|
4739
|
+
} catch (e) {
|
|
4740
|
+
}
|
|
4741
|
+
}
|
|
4742
|
+
throw new Error(`[MCPRegistry] Tool "${toolName}" not found on any registered MCP server.`);
|
|
4743
|
+
}
|
|
4744
|
+
disconnectAll() {
|
|
4745
|
+
this.clients.forEach((c) => c.disconnect());
|
|
4746
|
+
}
|
|
4747
|
+
};
|
|
4748
|
+
|
|
4749
|
+
// src/core/MultiAgentCoordinator.ts
|
|
4750
|
+
var MultiAgentCoordinator = class {
|
|
4751
|
+
constructor(options) {
|
|
4752
|
+
var _a2;
|
|
4753
|
+
this.llmProvider = options.llmProvider;
|
|
4754
|
+
this.mcpRegistry = options.mcpRegistry;
|
|
4755
|
+
this.documentSearch = options.documentSearch;
|
|
4756
|
+
this.maxIterations = (_a2 = options.maxIterations) != null ? _a2 : 5;
|
|
4757
|
+
}
|
|
4758
|
+
/**
|
|
4759
|
+
* Run the multi-agent coordination loop synchronously and return the final response.
|
|
4760
|
+
*/
|
|
4761
|
+
async run(question, history = []) {
|
|
4762
|
+
const generator = this.runStream(question, history);
|
|
4763
|
+
let finalReply = "";
|
|
4764
|
+
const sources = [];
|
|
4765
|
+
try {
|
|
4766
|
+
for (var iter = __forAwait(generator), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
4767
|
+
const chunk = temp.value;
|
|
4768
|
+
if (typeof chunk === "string") {
|
|
4769
|
+
finalReply += chunk;
|
|
4770
|
+
} else if (chunk && typeof chunk === "object") {
|
|
4771
|
+
if ("reply" in chunk && chunk.reply) {
|
|
4772
|
+
finalReply += chunk.reply;
|
|
4773
|
+
}
|
|
4774
|
+
if ("sources" in chunk && chunk.sources) {
|
|
4775
|
+
sources.push(...chunk.sources);
|
|
4776
|
+
}
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
} catch (temp) {
|
|
4780
|
+
error = [temp];
|
|
4781
|
+
} finally {
|
|
4782
|
+
try {
|
|
4783
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
4784
|
+
} finally {
|
|
4785
|
+
if (error)
|
|
4786
|
+
throw error[0];
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
return {
|
|
4790
|
+
reply: finalReply,
|
|
4791
|
+
sources
|
|
4792
|
+
};
|
|
4793
|
+
}
|
|
4794
|
+
/**
|
|
4795
|
+
* Run the multi-agent coordination loop as an async stream, yielding intermediate thought blocks and tool execution events.
|
|
4796
|
+
*/
|
|
4797
|
+
runStream(_0) {
|
|
4798
|
+
return __asyncGenerator(this, arguments, function* (question, history = []) {
|
|
4799
|
+
const mcpTools = yield new __await(this.mcpRegistry.getAllTools());
|
|
4800
|
+
let systemPrompt = `You are a goal-driven supervisor agent coordinating a RAG search engine and external MCP servers to solve the user's task.
|
|
4801
|
+
You must think step-by-step before acting. Write your internal thinking process inside a \`<think>...</think>\` block first, then act or answer.
|
|
4802
|
+
|
|
4803
|
+
Available Tools:
|
|
4804
|
+
- document_search(query: string): Search the vector database and knowledge base for documents.
|
|
4805
|
+
|
|
4806
|
+
${mcpTools.length > 0 ? "MCP Server Tools:" : ""}
|
|
4807
|
+
${mcpTools.map((mt) => {
|
|
4808
|
+
var _a2;
|
|
4809
|
+
return `- ${mt.tool.name}(${JSON.stringify(((_a2 = mt.tool.inputSchema) == null ? void 0 : _a2.properties) || {})}): ${mt.tool.description || "No description provided."}`;
|
|
4810
|
+
}).join("\n")}
|
|
4811
|
+
|
|
4812
|
+
Tool Calling Protocol:
|
|
4813
|
+
If you need to call a tool, write:
|
|
4814
|
+
TOOL_CALL: <toolName>({ "argName": "value" })
|
|
4815
|
+
And then STOP generating immediately.
|
|
4816
|
+
|
|
4817
|
+
Once you have gathered enough information to fully satisfy the user's query, write your final response directly after the closing \`</think>\` block.
|
|
4818
|
+
`;
|
|
4819
|
+
const supervisorHistory = [
|
|
4820
|
+
{ role: "system", content: systemPrompt },
|
|
4821
|
+
...history,
|
|
4822
|
+
{ role: "user", content: question }
|
|
4823
|
+
];
|
|
4824
|
+
let iteration = 0;
|
|
4825
|
+
const allSources = [];
|
|
4826
|
+
while (iteration < this.maxIterations) {
|
|
4827
|
+
iteration++;
|
|
4828
|
+
const context = "";
|
|
4829
|
+
let fullModelResponse = "";
|
|
4830
|
+
let textBuffer = "";
|
|
4831
|
+
let inThinking = false;
|
|
4832
|
+
let toolCallDetected = null;
|
|
4833
|
+
if (!this.llmProvider.chatStream) {
|
|
4834
|
+
const reply = yield new __await(this.llmProvider.chat(supervisorHistory, context));
|
|
4835
|
+
fullModelResponse = reply;
|
|
4836
|
+
const thinkIndex = reply.indexOf("<think>");
|
|
4837
|
+
const endThinkIndex = reply.indexOf("</think>");
|
|
4838
|
+
let thinkingText = "";
|
|
4839
|
+
let answerText = reply;
|
|
4840
|
+
if (thinkIndex !== -1 && endThinkIndex !== -1) {
|
|
4841
|
+
thinkingText = reply.substring(thinkIndex + 7, endThinkIndex);
|
|
4842
|
+
answerText = reply.substring(endThinkIndex + 8);
|
|
4843
|
+
yield { type: "thinking", text: thinkingText };
|
|
4844
|
+
}
|
|
4845
|
+
const toolMatch = answerText.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4846
|
+
if (toolMatch) {
|
|
4847
|
+
const toolName = toolMatch[1];
|
|
4848
|
+
const toolArgsStr = toolMatch[2];
|
|
4849
|
+
try {
|
|
4850
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4851
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4852
|
+
} catch (e) {
|
|
4853
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4854
|
+
}
|
|
4855
|
+
} else {
|
|
4856
|
+
yield answerText;
|
|
4857
|
+
}
|
|
4858
|
+
} else {
|
|
4859
|
+
const stream = this.llmProvider.chatStream(supervisorHistory, context);
|
|
4860
|
+
try {
|
|
4861
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
4862
|
+
const chunk = temp.value;
|
|
4863
|
+
fullModelResponse += chunk;
|
|
4864
|
+
textBuffer += chunk;
|
|
4865
|
+
if (!inThinking && textBuffer.includes("<think>")) {
|
|
4866
|
+
inThinking = true;
|
|
4867
|
+
const idx = textBuffer.indexOf("<think>");
|
|
4868
|
+
textBuffer = textBuffer.slice(idx + 7);
|
|
4869
|
+
}
|
|
4870
|
+
if (inThinking && textBuffer.includes("</think>")) {
|
|
4871
|
+
inThinking = false;
|
|
4872
|
+
const idx = textBuffer.indexOf("</think>");
|
|
4873
|
+
const thinkingDelta = textBuffer.slice(0, idx);
|
|
4874
|
+
yield { type: "thinking", text: thinkingDelta };
|
|
4875
|
+
textBuffer = textBuffer.slice(idx + 8);
|
|
4876
|
+
}
|
|
4877
|
+
if (inThinking && textBuffer.length > 0) {
|
|
4878
|
+
yield { type: "thinking", text: textBuffer };
|
|
4879
|
+
textBuffer = "";
|
|
4880
|
+
}
|
|
4881
|
+
if (!inThinking && textBuffer.includes("TOOL_CALL:")) {
|
|
4882
|
+
const idx = textBuffer.indexOf("TOOL_CALL:");
|
|
4883
|
+
const precedingText = textBuffer.slice(0, idx);
|
|
4884
|
+
if (precedingText.trim()) {
|
|
4885
|
+
yield precedingText;
|
|
4886
|
+
}
|
|
4887
|
+
textBuffer = textBuffer.slice(idx);
|
|
4888
|
+
}
|
|
4889
|
+
if (!inThinking && !textBuffer.includes("TOOL_CALL:") && textBuffer.length > 0) {
|
|
4890
|
+
yield textBuffer;
|
|
4891
|
+
textBuffer = "";
|
|
4892
|
+
}
|
|
4893
|
+
}
|
|
4894
|
+
} catch (temp) {
|
|
4895
|
+
error = [temp];
|
|
4896
|
+
} finally {
|
|
4897
|
+
try {
|
|
4898
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
4899
|
+
} finally {
|
|
4900
|
+
if (error)
|
|
4901
|
+
throw error[0];
|
|
4902
|
+
}
|
|
4903
|
+
}
|
|
4904
|
+
if (textBuffer.trim()) {
|
|
4905
|
+
const toolMatch = textBuffer.match(/TOOL_CALL:\s*(\w+)\s*\(([\s\S]*)\)/);
|
|
4906
|
+
if (toolMatch) {
|
|
4907
|
+
const toolName = toolMatch[1];
|
|
4908
|
+
const toolArgsStr = toolMatch[2];
|
|
4909
|
+
try {
|
|
4910
|
+
const toolArgs = JSON.parse(toolArgsStr.trim());
|
|
4911
|
+
toolCallDetected = { name: toolName, args: toolArgs };
|
|
4912
|
+
} catch (e) {
|
|
4913
|
+
console.error("[MultiAgentCoordinator] Failed to parse tool args:", toolArgsStr, e);
|
|
4914
|
+
}
|
|
4915
|
+
} else {
|
|
4916
|
+
yield textBuffer;
|
|
4917
|
+
}
|
|
4918
|
+
}
|
|
4919
|
+
}
|
|
4920
|
+
supervisorHistory.push({ role: "assistant", content: fullModelResponse });
|
|
4921
|
+
if (toolCallDetected) {
|
|
4922
|
+
const { name: toolName, args: toolArgs } = toolCallDetected;
|
|
4923
|
+
yield {
|
|
4924
|
+
type: "thinking",
|
|
4925
|
+
text: `
|
|
4926
|
+
[Agent Call] Executing tool "${toolName}" with parameters ${JSON.stringify(toolArgs)}...
|
|
4927
|
+
`
|
|
4928
|
+
};
|
|
4929
|
+
let toolResultText = "";
|
|
4930
|
+
try {
|
|
4931
|
+
if (toolName === "document_search") {
|
|
4932
|
+
const searchRes = yield new __await(this.documentSearch(toolArgs.query || ""));
|
|
4933
|
+
toolResultText = `document_search returned:
|
|
4934
|
+
${searchRes.reply}
|
|
4935
|
+
|
|
4936
|
+
Sources count: ${searchRes.sources.length}`;
|
|
4937
|
+
if (searchRes.sources && searchRes.sources.length > 0) {
|
|
4938
|
+
allSources.push(...searchRes.sources);
|
|
4939
|
+
yield { reply: "", sources: searchRes.sources };
|
|
4940
|
+
}
|
|
4941
|
+
} else {
|
|
4942
|
+
const mcpRes = yield new __await(this.mcpRegistry.callTool(toolName, toolArgs));
|
|
4943
|
+
toolResultText = `MCP Tool "${toolName}" returned:
|
|
4944
|
+
${JSON.stringify(mcpRes.content)}`;
|
|
4945
|
+
}
|
|
4946
|
+
} catch (err) {
|
|
4947
|
+
toolResultText = `Error calling tool "${toolName}": ${err.message}`;
|
|
4948
|
+
}
|
|
4949
|
+
supervisorHistory.push({
|
|
4950
|
+
role: "user",
|
|
4951
|
+
content: `TOOL_RESULT for ${toolName}:
|
|
4952
|
+
${toolResultText}`
|
|
4953
|
+
});
|
|
4954
|
+
yield {
|
|
4955
|
+
type: "thinking",
|
|
4956
|
+
text: `[Agent Output] Tool "${toolName}" executed. Continuing reasoning...
|
|
4957
|
+
`
|
|
4958
|
+
};
|
|
4959
|
+
} else {
|
|
4960
|
+
break;
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
});
|
|
4964
|
+
}
|
|
4965
|
+
};
|
|
4966
|
+
|
|
4185
4967
|
// src/core/BatchProcessor.ts
|
|
4186
4968
|
function isTransientError(error) {
|
|
4187
4969
|
if (!(error instanceof Error)) return false;
|
|
@@ -4502,7 +5284,7 @@ var QueryProcessor = class {
|
|
|
4502
5284
|
* @param validFields Optional list of known filterable fields to look for
|
|
4503
5285
|
*/
|
|
4504
5286
|
static extractQueryFieldHints(question, validFields = []) {
|
|
4505
|
-
var
|
|
5287
|
+
var _a2, _b, _c, _d;
|
|
4506
5288
|
if (!question.trim()) return [];
|
|
4507
5289
|
const hints = /* @__PURE__ */ new Map();
|
|
4508
5290
|
const addHint = (value, field) => {
|
|
@@ -4582,7 +5364,7 @@ var QueryProcessor = class {
|
|
|
4582
5364
|
];
|
|
4583
5365
|
for (const p of universalPatterns) {
|
|
4584
5366
|
for (const match of question.matchAll(p.regex)) {
|
|
4585
|
-
const val = p.group ? (
|
|
5367
|
+
const val = p.group ? (_a2 = match[p.group]) != null ? _a2 : match[0] : match[0];
|
|
4586
5368
|
if (!val) continue;
|
|
4587
5369
|
if (p.field) addHint(val, p.field);
|
|
4588
5370
|
else addHint(val);
|
|
@@ -4806,11 +5588,11 @@ var LLMRouter = class {
|
|
|
4806
5588
|
* When provided it is used directly as the 'default' role without re-constructing.
|
|
4807
5589
|
*/
|
|
4808
5590
|
async initialize(prebuiltDefault) {
|
|
4809
|
-
var
|
|
5591
|
+
var _a2;
|
|
4810
5592
|
const defaultModel = prebuiltDefault != null ? prebuiltDefault : LLMFactory.create(this.config.llm, this.config.embedding);
|
|
4811
5593
|
this.models.set("default", defaultModel);
|
|
4812
5594
|
const envFastModel = process.env.FAST_LLM_MODEL;
|
|
4813
|
-
const providerFastDefault = (
|
|
5595
|
+
const providerFastDefault = (_a2 = FAST_MODEL_DEFAULTS[this.config.llm.provider]) != null ? _a2 : "";
|
|
4814
5596
|
const fastModelName = envFastModel || providerFastDefault;
|
|
4815
5597
|
if (fastModelName && fastModelName !== this.config.llm.model) {
|
|
4816
5598
|
console.log(`[LLMRouter] Fast role \u2192 provider="${this.config.llm.provider}" model="${fastModelName}"`);
|
|
@@ -4829,8 +5611,8 @@ var LLMRouter = class {
|
|
|
4829
5611
|
* Falls back to 'default' if the requested role is not registered.
|
|
4830
5612
|
*/
|
|
4831
5613
|
get(role) {
|
|
4832
|
-
var
|
|
4833
|
-
const provider = (
|
|
5614
|
+
var _a2;
|
|
5615
|
+
const provider = (_a2 = this.models.get(role)) != null ? _a2 : this.models.get("default");
|
|
4834
5616
|
if (!provider) {
|
|
4835
5617
|
throw new Error(`[LLMRouter] No provider registered for role: "${role}". Did you call initialize()?`);
|
|
4836
5618
|
}
|
|
@@ -4848,7 +5630,7 @@ var UITransformer = class _UITransformer {
|
|
|
4848
5630
|
* Prefer `analyzeAndDecide()` in production.
|
|
4849
5631
|
*/
|
|
4850
5632
|
static transform(userQuery, retrievedData, config, trainedSchema, intent) {
|
|
4851
|
-
var
|
|
5633
|
+
var _a2, _b, _c;
|
|
4852
5634
|
if (!retrievedData || retrievedData.length === 0) {
|
|
4853
5635
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
4854
5636
|
}
|
|
@@ -4868,7 +5650,7 @@ var UITransformer = class _UITransformer {
|
|
|
4868
5650
|
return this.transformToBarChart(filteredData, profile, userQuery, resolvedIntent.visualizationHint === "ranking");
|
|
4869
5651
|
}
|
|
4870
5652
|
if (resolvedIntent.visualizationHint === "distribution") {
|
|
4871
|
-
return (
|
|
5653
|
+
return (_a2 = this.transformToHistogram(profile, userQuery)) != null ? _a2 : this.transformToBarChart(filteredData, profile, userQuery);
|
|
4872
5654
|
}
|
|
4873
5655
|
if (resolvedIntent.visualizationHint === "correlation") {
|
|
4874
5656
|
return (_b = this.transformToScatterPlot(profile, userQuery)) != null ? _b : this.transformToBarChart(filteredData, profile, userQuery);
|
|
@@ -5193,11 +5975,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5193
5975
|
};
|
|
5194
5976
|
}
|
|
5195
5977
|
static transformToPieChart(data, profile, query = "") {
|
|
5196
|
-
var
|
|
5978
|
+
var _a2;
|
|
5197
5979
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5198
5980
|
const categories = dimension ? Array.from(new Set(profile.records.map((record) => {
|
|
5199
|
-
var
|
|
5200
|
-
return String((
|
|
5981
|
+
var _a3;
|
|
5982
|
+
return String((_a3 = record.fields[dimension.key]) != null ? _a3 : "");
|
|
5201
5983
|
}).filter(Boolean))) : this.detectCategories(data);
|
|
5202
5984
|
if (categories.length === 0) return null;
|
|
5203
5985
|
const categoryData = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key) : this.aggregateByCategory(data, categories);
|
|
@@ -5207,7 +5989,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5207
5989
|
});
|
|
5208
5990
|
return {
|
|
5209
5991
|
type: "pie_chart",
|
|
5210
|
-
title: `Distribution by ${(
|
|
5992
|
+
title: `Distribution by ${(_a2 = dimension == null ? void 0 : dimension.label) != null ? _a2 : "Category"}`,
|
|
5211
5993
|
description: `Showing breakdown across ${pieData.length} categories`,
|
|
5212
5994
|
data: pieData
|
|
5213
5995
|
};
|
|
@@ -5217,8 +5999,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5217
5999
|
const valueField = profile.numericFields[0];
|
|
5218
6000
|
const buckets = /* @__PURE__ */ new Map();
|
|
5219
6001
|
profile.records.forEach((record) => {
|
|
5220
|
-
var
|
|
5221
|
-
const timestamp = String((
|
|
6002
|
+
var _a2, _b, _c;
|
|
6003
|
+
const timestamp = String((_a2 = record.fields[dateField.key]) != null ? _a2 : "");
|
|
5222
6004
|
const value = (_b = this.toFiniteNumber(record.fields[valueField.key])) != null ? _b : 0;
|
|
5223
6005
|
buckets.set(timestamp, ((_c = buckets.get(timestamp)) != null ? _c : 0) + value);
|
|
5224
6006
|
});
|
|
@@ -5231,23 +6013,23 @@ ${schemaProfileText}` : ""}`;
|
|
|
5231
6013
|
};
|
|
5232
6014
|
}
|
|
5233
6015
|
static transformToBarChart(data, profile, query = "", horizontal = false) {
|
|
5234
|
-
var
|
|
6016
|
+
var _a2;
|
|
5235
6017
|
const dimension = profile ? this.selectDimensionField(profile, query) : void 0;
|
|
5236
6018
|
const measure = profile ? this.selectNumericField(profile, query) : void 0;
|
|
5237
6019
|
const aggregate = dimension && profile ? this.aggregateProfileByDimension(profile, dimension.key, measure == null ? void 0 : measure.key) : this.aggregateByCategory(data, this.detectCategories(data));
|
|
5238
6020
|
const barData = Object.entries(aggregate).map(([category, value]) => ({ category, value: Number(value) })).sort((a, b) => horizontal ? b.value - a.value : 0).slice(0, 12);
|
|
5239
6021
|
const fallbackData = barData.length > 0 ? barData : data.slice(0, 12).map((item, index) => {
|
|
5240
|
-
var
|
|
6022
|
+
var _a3, _b, _c, _d, _e;
|
|
5241
6023
|
const meta = item.metadata || {};
|
|
5242
6024
|
const label = String(
|
|
5243
|
-
(_c = (_b = (
|
|
6025
|
+
(_c = (_b = (_a3 = this.getDynamicVal(meta, "name")) != null ? _a3 : meta.label) != null ? _b : meta.title) != null ? _c : `Result ${index + 1}`
|
|
5244
6026
|
);
|
|
5245
6027
|
const value = (_e = (_d = this.extractNumericValue(meta)) != null ? _d : item.score) != null ? _e : 0;
|
|
5246
6028
|
return { category: label, value: Number(value) };
|
|
5247
6029
|
});
|
|
5248
6030
|
return {
|
|
5249
6031
|
type: horizontal ? "horizontal_bar" : "bar_chart",
|
|
5250
|
-
title: dimension ? `${(
|
|
6032
|
+
title: dimension ? `${(_a2 = measure == null ? void 0 : measure.label) != null ? _a2 : "Count"} by ${dimension.label}` : "Comparison",
|
|
5251
6033
|
description: `Showing ${fallbackData.length} comparable values`,
|
|
5252
6034
|
data: fallbackData
|
|
5253
6035
|
};
|
|
@@ -5282,11 +6064,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
5282
6064
|
if (fields.length < 2) return null;
|
|
5283
6065
|
const [xField, yField] = fields;
|
|
5284
6066
|
const points = profile.records.map((record) => {
|
|
5285
|
-
var
|
|
6067
|
+
var _a2;
|
|
5286
6068
|
const x = this.toFiniteNumber(record.fields[xField.key]);
|
|
5287
6069
|
const y = this.toFiniteNumber(record.fields[yField.key]);
|
|
5288
6070
|
if (x === null || y === null) return null;
|
|
5289
|
-
return { x, y, label: String((
|
|
6071
|
+
return { x, y, label: String((_a2 = this.getRecordLabel(record)) != null ? _a2 : record.id) };
|
|
5290
6072
|
}).filter((point) => point !== null).slice(0, 100);
|
|
5291
6073
|
if (points.length === 0) return null;
|
|
5292
6074
|
return {
|
|
@@ -5316,9 +6098,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5316
6098
|
static transformToRadarChart(data) {
|
|
5317
6099
|
const attributeMap = {};
|
|
5318
6100
|
data.forEach((item) => {
|
|
5319
|
-
var
|
|
6101
|
+
var _a2, _b, _c;
|
|
5320
6102
|
const meta = item.metadata || {};
|
|
5321
|
-
const seriesName = String((_c = (_b = (
|
|
6103
|
+
const seriesName = String((_c = (_b = (_a2 = meta.name) != null ? _a2 : meta.product) != null ? _b : item.id) != null ? _c : "Item");
|
|
5322
6104
|
Object.entries(meta).forEach(([key, val]) => {
|
|
5323
6105
|
if (typeof val === "number" && !["price", "id"].includes(key.toLowerCase())) {
|
|
5324
6106
|
if (!attributeMap[key]) attributeMap[key] = {};
|
|
@@ -5400,22 +6182,22 @@ ${schemaProfileText}` : ""}`;
|
|
|
5400
6182
|
return null;
|
|
5401
6183
|
}
|
|
5402
6184
|
static normalizeTransformation(payload) {
|
|
5403
|
-
var
|
|
6185
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j;
|
|
5404
6186
|
if (!payload || typeof payload !== "object") return null;
|
|
5405
6187
|
const p = payload;
|
|
5406
6188
|
const type = this.normalizeVisualizationType(
|
|
5407
|
-
String((_c = (_b = (
|
|
6189
|
+
String((_c = (_b = (_a2 = p.type) != null ? _a2 : p.view) != null ? _b : p.chartType) != null ? _c : "")
|
|
5408
6190
|
);
|
|
5409
6191
|
if (!type) return null;
|
|
5410
6192
|
const title = String((_e = (_d = p.title) != null ? _d : p.heading) != null ? _e : "Visualization");
|
|
5411
6193
|
const description = p.description ? String(p.description) : void 0;
|
|
5412
|
-
const rawData = (_j = (_i = (_h = (
|
|
6194
|
+
const rawData = (_j = (_i = (_h = (_g2 = (_f = p.data) != null ? _f : p.table) != null ? _g2 : p.rows) != null ? _h : p.items) != null ? _i : p.content) != null ? _j : null;
|
|
5413
6195
|
const data = type === "text" && typeof rawData === "string" ? { content: rawData } : rawData;
|
|
5414
6196
|
const transformation = { type, title, description, data };
|
|
5415
6197
|
return this.validateTransformation(transformation) ? transformation : null;
|
|
5416
6198
|
}
|
|
5417
6199
|
static normalizeVisualizationType(type) {
|
|
5418
|
-
var
|
|
6200
|
+
var _a2;
|
|
5419
6201
|
const mapping = {
|
|
5420
6202
|
pie: "pie_chart",
|
|
5421
6203
|
pie_chart: "pie_chart",
|
|
@@ -5443,7 +6225,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5443
6225
|
product_carousel: "product_carousel",
|
|
5444
6226
|
carousel: "carousel"
|
|
5445
6227
|
};
|
|
5446
|
-
return (
|
|
6228
|
+
return (_a2 = mapping[type.toLowerCase()]) != null ? _a2 : null;
|
|
5447
6229
|
}
|
|
5448
6230
|
static validateTransformation(t) {
|
|
5449
6231
|
const { type, data } = t;
|
|
@@ -5645,16 +6427,16 @@ ${schemaProfileText}` : ""}`;
|
|
|
5645
6427
|
return null;
|
|
5646
6428
|
}
|
|
5647
6429
|
static selectDimensionField(profile, query) {
|
|
5648
|
-
var
|
|
6430
|
+
var _a2, _b;
|
|
5649
6431
|
const productCategory = profile.categoricalFields.find(
|
|
5650
6432
|
(field) => /category|department|collection|type|group|segment|region|country|state|city/i.test(field.key)
|
|
5651
6433
|
);
|
|
5652
6434
|
const ranked = this.rankFieldsByQuery(profile.categoricalFields, query);
|
|
5653
|
-
return (_b = (
|
|
6435
|
+
return (_b = (_a2 = ranked[0]) != null ? _a2 : productCategory) != null ? _b : profile.categoricalFields[0];
|
|
5654
6436
|
}
|
|
5655
6437
|
static selectNumericField(profile, query) {
|
|
5656
|
-
var
|
|
5657
|
-
return (
|
|
6438
|
+
var _a2;
|
|
6439
|
+
return (_a2 = this.rankFieldsByQuery(profile.numericFields, query)[0]) != null ? _a2 : profile.numericFields[0];
|
|
5658
6440
|
}
|
|
5659
6441
|
static rankFieldsByQuery(fields, query) {
|
|
5660
6442
|
const q = query.toLowerCase();
|
|
@@ -5683,8 +6465,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5683
6465
|
static aggregateProfileByDimension(profile, dimensionKey, measureKey) {
|
|
5684
6466
|
const result = {};
|
|
5685
6467
|
profile.records.forEach((record) => {
|
|
5686
|
-
var
|
|
5687
|
-
const category = String((
|
|
6468
|
+
var _a2, _b, _c;
|
|
6469
|
+
const category = String((_a2 = record.fields[dimensionKey]) != null ? _a2 : "Other").trim() || "Other";
|
|
5688
6470
|
const value = measureKey ? (_b = this.toFiniteNumber(record.fields[measureKey])) != null ? _b : 0 : 1;
|
|
5689
6471
|
result[category] = ((_c = result[category]) != null ? _c : 0) + value;
|
|
5690
6472
|
});
|
|
@@ -5763,8 +6545,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5763
6545
|
static aggregateByCategory(data, categories) {
|
|
5764
6546
|
const result = Object.fromEntries(categories.map((c) => [c, 0]));
|
|
5765
6547
|
data.forEach((item) => {
|
|
5766
|
-
var
|
|
5767
|
-
const cat = (
|
|
6548
|
+
var _a2;
|
|
6549
|
+
const cat = (_a2 = this.getProductCategory(item)) != null ? _a2 : "Other";
|
|
5768
6550
|
if (Object.prototype.hasOwnProperty.call(result, cat)) result[cat]++;
|
|
5769
6551
|
else result["Other"] = (result["Other"] || 0) + 1;
|
|
5770
6552
|
});
|
|
@@ -5772,17 +6554,17 @@ ${schemaProfileText}` : ""}`;
|
|
|
5772
6554
|
}
|
|
5773
6555
|
static extractTimeSeriesData(data) {
|
|
5774
6556
|
return data.map((item) => {
|
|
5775
|
-
var
|
|
6557
|
+
var _a2, _b, _c, _d, _e;
|
|
5776
6558
|
const meta = item.metadata || {};
|
|
5777
6559
|
return {
|
|
5778
|
-
timestamp: (_b = (
|
|
6560
|
+
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
5779
6561
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
5780
6562
|
label: (_e = meta.label) != null ? _e : item.content.substring(0, 50)
|
|
5781
6563
|
};
|
|
5782
6564
|
});
|
|
5783
6565
|
}
|
|
5784
6566
|
static extractNumericValue(meta) {
|
|
5785
|
-
var
|
|
6567
|
+
var _a2;
|
|
5786
6568
|
const preferredKeys = [
|
|
5787
6569
|
"value",
|
|
5788
6570
|
"count",
|
|
@@ -5797,7 +6579,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5797
6579
|
"price"
|
|
5798
6580
|
];
|
|
5799
6581
|
for (const key of preferredKeys) {
|
|
5800
|
-
const raw = (
|
|
6582
|
+
const raw = (_a2 = resolveMetadataValue(meta, key)) != null ? _a2 : meta[key];
|
|
5801
6583
|
const value = typeof raw === "number" ? raw : Number(String(raw != null ? raw : "").replace(/[$,% ,]/g, ""));
|
|
5802
6584
|
if (Number.isFinite(value)) return value;
|
|
5803
6585
|
}
|
|
@@ -5943,8 +6725,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
5943
6725
|
let inStock = 0;
|
|
5944
6726
|
let outOfStock = 0;
|
|
5945
6727
|
data.forEach((d) => {
|
|
5946
|
-
var
|
|
5947
|
-
const cat = (
|
|
6728
|
+
var _a2, _b;
|
|
6729
|
+
const cat = (_a2 = this.getProductCategory(d)) != null ? _a2 : "Other";
|
|
5948
6730
|
if (cat === category) {
|
|
5949
6731
|
const quantity = (_b = this.extractStockQuantity(d)) != null ? _b : 1;
|
|
5950
6732
|
if (this.determineStockStatus(d)) inStock += quantity;
|
|
@@ -5988,9 +6770,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
5988
6770
|
}
|
|
5989
6771
|
// ─── Product Extraction ───────────────────────────────────────────────────
|
|
5990
6772
|
static getDynamicVal(meta, uiKey, config, trainedSchema) {
|
|
5991
|
-
var
|
|
6773
|
+
var _a2;
|
|
5992
6774
|
if (!meta) return void 0;
|
|
5993
|
-
const mapping = (
|
|
6775
|
+
const mapping = (_a2 = config == null ? void 0 : config.rag) == null ? void 0 : _a2.uiMapping;
|
|
5994
6776
|
if ((mapping == null ? void 0 : mapping[uiKey]) && meta[mapping[uiKey]] !== void 0) return meta[mapping[uiKey]];
|
|
5995
6777
|
if (trainedSchema && typeof trainedSchema === "object") {
|
|
5996
6778
|
const trainedKey = trainedSchema[uiKey];
|
|
@@ -5999,13 +6781,13 @@ ${schemaProfileText}` : ""}`;
|
|
|
5999
6781
|
return resolveMetadataValue(meta, uiKey);
|
|
6000
6782
|
}
|
|
6001
6783
|
static extractProductInfo(item, config, trainedSchema) {
|
|
6002
|
-
var
|
|
6784
|
+
var _a2;
|
|
6003
6785
|
const meta = item.metadata || {};
|
|
6004
6786
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
6005
6787
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
6006
6788
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
6007
6789
|
const description = this.cleanProductDescription(
|
|
6008
|
-
(
|
|
6790
|
+
(_a2 = this.extractProductDescriptionFromContent(item.content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
6009
6791
|
);
|
|
6010
6792
|
if (name || this.isProductData(item)) {
|
|
6011
6793
|
let finalName = name ? String(name) : void 0;
|
|
@@ -6113,10 +6895,10 @@ RULES:
|
|
|
6113
6895
|
}
|
|
6114
6896
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
6115
6897
|
const items = sources.map((s, i) => {
|
|
6116
|
-
var
|
|
6898
|
+
var _a2, _b, _c, _d;
|
|
6117
6899
|
return {
|
|
6118
6900
|
index: i + 1,
|
|
6119
|
-
content: (_b = (
|
|
6901
|
+
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
6120
6902
|
metadata: (_c = s.metadata) != null ? _c : {},
|
|
6121
6903
|
score: (_d = s.score) != null ? _d : 0
|
|
6122
6904
|
};
|
|
@@ -6309,9 +7091,11 @@ var Pipeline = class {
|
|
|
6309
7091
|
/** LRU-bounded cache: avoids re-embedding identical queries within the same process. */
|
|
6310
7092
|
this.embeddingCache = new LRUEmbeddingCache(500);
|
|
6311
7093
|
this.initialised = false;
|
|
6312
|
-
|
|
7094
|
+
/** Namespace-specific static cold context cache for CAG */
|
|
7095
|
+
this.coldContexts = /* @__PURE__ */ new Map();
|
|
7096
|
+
var _a2, _b, _c, _d, _e;
|
|
6313
7097
|
this.chunker = new DocumentChunker(
|
|
6314
|
-
(_b = (
|
|
7098
|
+
(_b = (_a2 = config.rag) == null ? void 0 : _a2.chunkSize) != null ? _b : 1e3,
|
|
6315
7099
|
(_d = (_c = config.rag) == null ? void 0 : _c.chunkOverlap) != null ? _d : 200
|
|
6316
7100
|
);
|
|
6317
7101
|
if (((_e = config.rag) == null ? void 0 : _e.chunkingStrategy) === "llamaindex") {
|
|
@@ -6327,7 +7111,7 @@ var Pipeline = class {
|
|
|
6327
7111
|
return this.initialised ? this.llmProvider : void 0;
|
|
6328
7112
|
}
|
|
6329
7113
|
async initialize() {
|
|
6330
|
-
var
|
|
7114
|
+
var _a2, _b, _c;
|
|
6331
7115
|
if (this.initialised) return;
|
|
6332
7116
|
const chartInstruction = `You are a helpful assistant. Use the provided context to answer questions accurately.
|
|
6333
7117
|
|
|
@@ -6370,12 +7154,47 @@ var Pipeline = class {
|
|
|
6370
7154
|
this.entityExtractor = new EntityExtractor(this.llmProvider);
|
|
6371
7155
|
}
|
|
6372
7156
|
await this.vectorDB.initialize();
|
|
6373
|
-
if (((
|
|
7157
|
+
if (((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) {
|
|
7158
|
+
this.mcpRegistry = new MCPRegistry(this.config.mcpServers || []);
|
|
7159
|
+
this.multiAgentCoordinator = new MultiAgentCoordinator({
|
|
7160
|
+
llmProvider: this.llmProvider,
|
|
7161
|
+
mcpRegistry: this.mcpRegistry,
|
|
7162
|
+
documentSearch: async (query) => {
|
|
7163
|
+
return this.runNormalQuery(query);
|
|
7164
|
+
}
|
|
7165
|
+
});
|
|
6374
7166
|
this.agent = new LangChainAgent(this, this.config);
|
|
6375
7167
|
await this.agent.initialize(this.llmProvider);
|
|
6376
7168
|
}
|
|
7169
|
+
if ((_c = (_b = this.config.rag) == null ? void 0 : _b.cag) == null ? void 0 : _c.enabled) {
|
|
7170
|
+
await this.loadColdContext(this.config.projectId);
|
|
7171
|
+
}
|
|
6377
7172
|
this.initialised = true;
|
|
6378
7173
|
}
|
|
7174
|
+
async loadColdContext(ns) {
|
|
7175
|
+
var _a2, _b;
|
|
7176
|
+
const cagConfig = (_a2 = this.config.rag) == null ? void 0 : _a2.cag;
|
|
7177
|
+
if (!cagConfig || !cagConfig.enabled) return;
|
|
7178
|
+
try {
|
|
7179
|
+
const coldNs = cagConfig.coldNamespace || ns;
|
|
7180
|
+
const limit = (_b = cagConfig.coldLimit) != null ? _b : 20;
|
|
7181
|
+
const queryText = cagConfig.coldQuery || "documentation";
|
|
7182
|
+
const queryVector = await this.embeddingProvider.embed(queryText, { taskType: "query" });
|
|
7183
|
+
const coldMatches = await this.vectorDB.query(queryVector, limit, coldNs);
|
|
7184
|
+
if (coldMatches.length > 0) {
|
|
7185
|
+
const formatted = coldMatches.map((m, i) => `[Cold Source ${i + 1}]
|
|
7186
|
+
${m.content}`).join("\n\n---\n\n");
|
|
7187
|
+
this.coldContexts.set(ns, formatted);
|
|
7188
|
+
console.log(`[Pipeline] Cold RAG (CAG) loaded ${coldMatches.length} documents into cached context for namespace: ${ns}`);
|
|
7189
|
+
} else {
|
|
7190
|
+
this.coldContexts.set(ns, "No cold context found.");
|
|
7191
|
+
console.warn(`[Pipeline] Cold RAG (CAG) initialized but no documents were found in namespace: ${coldNs}`);
|
|
7192
|
+
}
|
|
7193
|
+
} catch (err) {
|
|
7194
|
+
console.error(`[Pipeline] Failed to load Cold RAG (CAG) context for namespace ${ns}:`, err);
|
|
7195
|
+
this.coldContexts.set(ns, "Failed to load cold context.");
|
|
7196
|
+
}
|
|
7197
|
+
}
|
|
6379
7198
|
/**
|
|
6380
7199
|
* Ingest documents with automatic chunking, embedding, and batch upsert.
|
|
6381
7200
|
*/
|
|
@@ -6407,12 +7226,12 @@ var Pipeline = class {
|
|
|
6407
7226
|
}
|
|
6408
7227
|
/** Step 1: Chunk the document content. */
|
|
6409
7228
|
async prepareChunks(doc) {
|
|
6410
|
-
var
|
|
7229
|
+
var _a2, _b;
|
|
6411
7230
|
if (this.llamaIngestor) {
|
|
6412
7231
|
return this.llamaIngestor.chunk(doc.content, {
|
|
6413
7232
|
docId: doc.docId,
|
|
6414
7233
|
metadata: doc.metadata,
|
|
6415
|
-
chunkSize: (
|
|
7234
|
+
chunkSize: (_a2 = this.config.rag) == null ? void 0 : _a2.chunkSize,
|
|
6416
7235
|
chunkOverlap: (_b = this.config.rag) == null ? void 0 : _b.chunkOverlap
|
|
6417
7236
|
});
|
|
6418
7237
|
}
|
|
@@ -6483,12 +7302,37 @@ var Pipeline = class {
|
|
|
6483
7302
|
extractionOptions
|
|
6484
7303
|
);
|
|
6485
7304
|
}
|
|
7305
|
+
async runNormalQuery(question, history = [], namespace) {
|
|
7306
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7307
|
+
let reply = "";
|
|
7308
|
+
let sources = [];
|
|
7309
|
+
try {
|
|
7310
|
+
for (var iter = __forAwait(stream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7311
|
+
const chunk = temp.value;
|
|
7312
|
+
if (typeof chunk === "string") {
|
|
7313
|
+
reply += chunk;
|
|
7314
|
+
} else if (typeof chunk === "object" && chunk !== null) {
|
|
7315
|
+
if ("reply" in chunk && chunk.reply) reply += chunk.reply;
|
|
7316
|
+
if ("sources" in chunk && chunk.sources) sources = chunk.sources;
|
|
7317
|
+
}
|
|
7318
|
+
}
|
|
7319
|
+
} catch (temp) {
|
|
7320
|
+
error = [temp];
|
|
7321
|
+
} finally {
|
|
7322
|
+
try {
|
|
7323
|
+
more && (temp = iter.return) && await temp.call(iter);
|
|
7324
|
+
} finally {
|
|
7325
|
+
if (error)
|
|
7326
|
+
throw error[0];
|
|
7327
|
+
}
|
|
7328
|
+
}
|
|
7329
|
+
return { reply, sources };
|
|
7330
|
+
}
|
|
6486
7331
|
async ask(question, history = [], namespace) {
|
|
6487
|
-
var
|
|
7332
|
+
var _a2;
|
|
6488
7333
|
await this.initialize();
|
|
6489
|
-
if (((
|
|
6490
|
-
|
|
6491
|
-
return { reply: agentReply, sources: [] };
|
|
7334
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7335
|
+
return await this.multiAgentCoordinator.run(question, history);
|
|
6492
7336
|
}
|
|
6493
7337
|
const stream = this.askStream(question, history, namespace);
|
|
6494
7338
|
let reply = "";
|
|
@@ -6520,6 +7364,47 @@ var Pipeline = class {
|
|
|
6520
7364
|
}
|
|
6521
7365
|
return { reply, sources, graphData, ui_transformation: uiTransformation, trace };
|
|
6522
7366
|
}
|
|
7367
|
+
askStream(_0) {
|
|
7368
|
+
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
7369
|
+
var _a2;
|
|
7370
|
+
yield new __await(this.initialize());
|
|
7371
|
+
if ((((_a2 = this.config.rag) == null ? void 0 : _a2.architecture) === "agentic" || this.config.mcpServers && this.config.mcpServers.length > 0) && this.multiAgentCoordinator) {
|
|
7372
|
+
const stream2 = this.multiAgentCoordinator.runStream(question, history);
|
|
7373
|
+
try {
|
|
7374
|
+
for (var iter = __forAwait(stream2), more, temp, error; more = !(temp = yield new __await(iter.next())).done; more = false) {
|
|
7375
|
+
const chunk = temp.value;
|
|
7376
|
+
yield chunk;
|
|
7377
|
+
}
|
|
7378
|
+
} catch (temp) {
|
|
7379
|
+
error = [temp];
|
|
7380
|
+
} finally {
|
|
7381
|
+
try {
|
|
7382
|
+
more && (temp = iter.return) && (yield new __await(temp.call(iter)));
|
|
7383
|
+
} finally {
|
|
7384
|
+
if (error)
|
|
7385
|
+
throw error[0];
|
|
7386
|
+
}
|
|
7387
|
+
}
|
|
7388
|
+
return;
|
|
7389
|
+
}
|
|
7390
|
+
const stream = this.askStreamInternal(question, history, namespace);
|
|
7391
|
+
try {
|
|
7392
|
+
for (var iter2 = __forAwait(stream), more2, temp2, error2; more2 = !(temp2 = yield new __await(iter2.next())).done; more2 = false) {
|
|
7393
|
+
const chunk = temp2.value;
|
|
7394
|
+
yield chunk;
|
|
7395
|
+
}
|
|
7396
|
+
} catch (temp2) {
|
|
7397
|
+
error2 = [temp2];
|
|
7398
|
+
} finally {
|
|
7399
|
+
try {
|
|
7400
|
+
more2 && (temp2 = iter2.return) && (yield new __await(temp2.call(iter2)));
|
|
7401
|
+
} finally {
|
|
7402
|
+
if (error2)
|
|
7403
|
+
throw error2[0];
|
|
7404
|
+
}
|
|
7405
|
+
}
|
|
7406
|
+
});
|
|
7407
|
+
}
|
|
6523
7408
|
/**
|
|
6524
7409
|
* High-performance streaming RAG flow.
|
|
6525
7410
|
* Yields text chunks first, then the retrieval metadata + observability trace at the end.
|
|
@@ -6530,12 +7415,12 @@ var Pipeline = class {
|
|
|
6530
7415
|
* - UITransformation is computed after text streaming and emitted with metadata
|
|
6531
7416
|
* - SchemaMapper.train runs while answer generation streams
|
|
6532
7417
|
*/
|
|
6533
|
-
|
|
7418
|
+
askStreamInternal(_0) {
|
|
6534
7419
|
return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
|
|
6535
|
-
var
|
|
7420
|
+
var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
|
|
6536
7421
|
yield new __await(this.initialize());
|
|
6537
7422
|
const ns = namespace != null ? namespace : this.config.projectId;
|
|
6538
|
-
const topK = (_b = (
|
|
7423
|
+
const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
|
|
6539
7424
|
const scoreThreshold = (_d = (_c = this.config.rag) == null ? void 0 : _c.scoreThreshold) != null ? _d : 0.3;
|
|
6540
7425
|
const requestId = `req_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
6541
7426
|
const requestStart = performance.now();
|
|
@@ -6548,7 +7433,7 @@ var Pipeline = class {
|
|
|
6548
7433
|
}
|
|
6549
7434
|
const hints = QueryProcessor.extractQueryFieldHints(question, (_f = this.config.rag) == null ? void 0 : _f.filterableFields);
|
|
6550
7435
|
const filter = QueryProcessor.buildQueryFilter(question, hints);
|
|
6551
|
-
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (
|
|
7436
|
+
const numericPredicates = QueryProcessor.extractNumericPredicates(question, (_g2 = this.config.rag) == null ? void 0 : _g2.filterableFields);
|
|
6552
7437
|
if (numericPredicates.length > 0) {
|
|
6553
7438
|
filter.__numericPredicates = numericPredicates;
|
|
6554
7439
|
}
|
|
@@ -6614,6 +7499,32 @@ ${graphContext}
|
|
|
6614
7499
|
VECTOR CONTEXT:
|
|
6615
7500
|
${context}`;
|
|
6616
7501
|
}
|
|
7502
|
+
if ((_n = (_m = this.config.rag) == null ? void 0 : _m.cag) == null ? void 0 : _n.enabled) {
|
|
7503
|
+
if (!this.coldContexts.has(ns)) {
|
|
7504
|
+
yield new __await(this.loadColdContext(ns));
|
|
7505
|
+
}
|
|
7506
|
+
const coldContext = this.coldContexts.get(ns);
|
|
7507
|
+
if (coldContext && coldContext !== "No cold context found." && coldContext !== "Failed to load cold context.") {
|
|
7508
|
+
context = `COLD CONTEXT (STATIC KNOWLEDGE):
|
|
7509
|
+
${coldContext}
|
|
7510
|
+
|
|
7511
|
+
RETRIEVED HOT CONTEXT (REAL-TIME KNOWLEDGE):
|
|
7512
|
+
${context}`;
|
|
7513
|
+
}
|
|
7514
|
+
}
|
|
7515
|
+
yield {
|
|
7516
|
+
reply: "",
|
|
7517
|
+
sources: sources.map((s) => {
|
|
7518
|
+
var _a3;
|
|
7519
|
+
return {
|
|
7520
|
+
id: s.id,
|
|
7521
|
+
score: s.score,
|
|
7522
|
+
content: s.content,
|
|
7523
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
7524
|
+
namespace: ns
|
|
7525
|
+
};
|
|
7526
|
+
})
|
|
7527
|
+
};
|
|
6617
7528
|
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
6618
7529
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
6619
7530
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
@@ -6641,10 +7552,10 @@ ${context}`;
|
|
|
6641
7552
|
let hallucinationScoringPromise = Promise.resolve(void 0);
|
|
6642
7553
|
const restrictionSuffix = "\n\n(IMPORTANT: Format your response beautifully using rich Markdown! Use bolding for emphasis, headings (##) for structure, bullet points for lists, and proper line breaks between paragraphs to make it highly readable. However, NEVER generate Markdown tables, HTML figures, or text charts (the UI renders requested charts separately, so NEVER say you cannot create, display, draw, render, or provide a chart/visualization). If listing products, use simple markdown bullet points or comma-separated names. NEVER use plus signs (+) to separate product names, category names, or list items. For product description/detail questions, provide customer-facing prose only and do NOT list internal catalog fields such as Handle, Body (HTML), Vendor, Type, Tags, Published, Option, Variant, SKU, or raw metadata labels. You CAN use numbers for years/counts like 2006 or 5800, but NEVER put a dollar sign ($) before them.)";
|
|
6643
7554
|
const isClaude37 = this.config.llm.model.includes("claude-3-7-sonnet");
|
|
6644
|
-
const isNativeThinking = isClaude37 && (((
|
|
7555
|
+
const isNativeThinking = isClaude37 && (((_o = this.config.llm.options) == null ? void 0 : _o.thinking) === true || ((_p = this.config.llm.options) == null ? void 0 : _p.thinking) === "enabled" || ((_q = this.config.llm.options) == null ? void 0 : _q.thinking) !== false);
|
|
6645
7556
|
const modelNameLower = this.config.llm.model.toLowerCase();
|
|
6646
7557
|
const isReasoningModel = modelNameLower.includes("-r1") || modelNameLower.includes("deepseek-r1") || modelNameLower.includes("reasoning") || modelNameLower.includes("thinking");
|
|
6647
|
-
const isSimulatedThinking = !isNativeThinking && (((
|
|
7558
|
+
const isSimulatedThinking = !isNativeThinking && (((_r = this.config.llm.options) == null ? void 0 : _r.thinking) === true || ((_s = this.config.llm.options) == null ? void 0 : _s.thinking) === "enabled" || isReasoningModel && ((_t = this.config.llm.options) == null ? void 0 : _t.thinking) !== false);
|
|
6648
7559
|
let finalRestrictionSuffix = restrictionSuffix;
|
|
6649
7560
|
if (isSimulatedThinking) {
|
|
6650
7561
|
finalRestrictionSuffix += "\n\n(IMPORTANT: You must think step-by-step before answering. Write your thinking process inside a `<think>...</think>` block. Write the `<think>` block first, then follow it with your final response. Keep the thinking process thorough and detailed. Example: `<think>Thinking details here...</think>Final answer text here.`)";
|
|
@@ -6652,7 +7563,7 @@ ${context}`;
|
|
|
6652
7563
|
const hardenedHistory = [...history];
|
|
6653
7564
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
6654
7565
|
const messages = [...hardenedHistory, userQuestion];
|
|
6655
|
-
const systemPrompt = (
|
|
7566
|
+
const systemPrompt = (_u = this.config.llm.systemPrompt) != null ? _u : "";
|
|
6656
7567
|
const userPrompt = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
|
|
6657
7568
|
let fullReply = "";
|
|
6658
7569
|
let thinkingText = "";
|
|
@@ -6763,7 +7674,7 @@ ${context}`;
|
|
|
6763
7674
|
}
|
|
6764
7675
|
yield fullReply;
|
|
6765
7676
|
}
|
|
6766
|
-
const runHallucination = ((
|
|
7677
|
+
const runHallucination = ((_v = this.config.llm.options) == null ? void 0 : _v.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) !== false;
|
|
6767
7678
|
if (runHallucination) {
|
|
6768
7679
|
hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
|
|
6769
7680
|
}
|
|
@@ -6772,7 +7683,7 @@ ${context}`;
|
|
|
6772
7683
|
const latency = {
|
|
6773
7684
|
embedMs: Math.round(embedMs),
|
|
6774
7685
|
retrieveMs: Math.round(retrieveMs),
|
|
6775
|
-
rerankMs: ((
|
|
7686
|
+
rerankMs: ((_x = this.config.rag) == null ? void 0 : _x.useReranking) ? Math.round(rerankMs) : void 0,
|
|
6776
7687
|
generateMs: Math.round(generateMs),
|
|
6777
7688
|
totalMs: Math.round(totalMs)
|
|
6778
7689
|
};
|
|
@@ -6785,33 +7696,63 @@ ${context}`;
|
|
|
6785
7696
|
totalTokens: promptTokens + completionTokens,
|
|
6786
7697
|
estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
|
|
6787
7698
|
};
|
|
7699
|
+
const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
|
|
6788
7700
|
const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
|
|
6789
7701
|
uiTransformationPromise,
|
|
6790
|
-
hallucinationScoringPromise
|
|
7702
|
+
awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
|
|
6791
7703
|
]));
|
|
6792
|
-
const
|
|
7704
|
+
const buildTrace = (hScore) => __spreadValues({
|
|
6793
7705
|
requestId,
|
|
6794
7706
|
query: question,
|
|
6795
7707
|
rewrittenQuery,
|
|
6796
7708
|
systemPrompt,
|
|
6797
7709
|
userPrompt: question + finalRestrictionSuffix,
|
|
6798
7710
|
chunks: sources.map((s) => {
|
|
6799
|
-
var
|
|
7711
|
+
var _a3;
|
|
6800
7712
|
return {
|
|
6801
7713
|
id: s.id,
|
|
6802
7714
|
score: s.score,
|
|
6803
7715
|
content: s.content,
|
|
6804
|
-
metadata: (
|
|
7716
|
+
metadata: (_a3 = s.metadata) != null ? _a3 : {},
|
|
6805
7717
|
namespace: ns
|
|
6806
7718
|
};
|
|
6807
7719
|
}),
|
|
6808
7720
|
latency,
|
|
6809
7721
|
tokens,
|
|
6810
7722
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6811
|
-
},
|
|
6812
|
-
hallucinationScore:
|
|
6813
|
-
hallucinationReason:
|
|
7723
|
+
}, hScore ? {
|
|
7724
|
+
hallucinationScore: hScore.score,
|
|
7725
|
+
hallucinationReason: hScore.reason
|
|
6814
7726
|
} : {});
|
|
7727
|
+
const trace = buildTrace(hallucinationResult);
|
|
7728
|
+
if ((_z = this.config.telemetry) == null ? void 0 : _z.enabled) {
|
|
7729
|
+
const telemetryUrl = this.config.telemetry.url || "/api/telemetry";
|
|
7730
|
+
const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
|
|
7731
|
+
(async () => {
|
|
7732
|
+
try {
|
|
7733
|
+
let finalTrace = trace;
|
|
7734
|
+
if (!awaitHallucination && runHallucination) {
|
|
7735
|
+
const backgroundScoreResult = await hallucinationScoringPromise;
|
|
7736
|
+
if (backgroundScoreResult) {
|
|
7737
|
+
finalTrace = buildTrace(backgroundScoreResult);
|
|
7738
|
+
}
|
|
7739
|
+
}
|
|
7740
|
+
await fetch(absoluteUrl, {
|
|
7741
|
+
method: "POST",
|
|
7742
|
+
headers: {
|
|
7743
|
+
"Content-Type": "application/json"
|
|
7744
|
+
},
|
|
7745
|
+
body: JSON.stringify({
|
|
7746
|
+
trace: finalTrace,
|
|
7747
|
+
licenseKey: this.config.licenseKey,
|
|
7748
|
+
projectId: ns
|
|
7749
|
+
})
|
|
7750
|
+
});
|
|
7751
|
+
} catch (err) {
|
|
7752
|
+
console.warn(`[Pipeline Telemetry] Failed to send trace async to ${absoluteUrl}:`, err.message);
|
|
7753
|
+
}
|
|
7754
|
+
})();
|
|
7755
|
+
}
|
|
6815
7756
|
yield {
|
|
6816
7757
|
reply: "",
|
|
6817
7758
|
sources,
|
|
@@ -6831,7 +7772,7 @@ ${context}`;
|
|
|
6831
7772
|
* Uses an LRU-bounded embedding cache to avoid re-embedding the same query.
|
|
6832
7773
|
*/
|
|
6833
7774
|
async generateUiTransformation(question, sources, cachedSchema, forceDeterministic = false) {
|
|
6834
|
-
var
|
|
7775
|
+
var _a2;
|
|
6835
7776
|
if (!sources || sources.length === 0) {
|
|
6836
7777
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6837
7778
|
}
|
|
@@ -6845,7 +7786,7 @@ ${context}`;
|
|
|
6845
7786
|
);
|
|
6846
7787
|
}
|
|
6847
7788
|
const isLocalProvider = this.config.llm.provider === "ollama";
|
|
6848
|
-
const disableLlmUiTransform = ((
|
|
7789
|
+
const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
|
|
6849
7790
|
if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
|
|
6850
7791
|
return UITransformer.transform(question, sources, this.config, cachedSchema);
|
|
6851
7792
|
}
|
|
@@ -6863,9 +7804,9 @@ ${context}`;
|
|
|
6863
7804
|
const value = this.resolveNumericPredicateValue(source, predicate);
|
|
6864
7805
|
return value !== null && this.matchesNumericPredicate(value, predicate);
|
|
6865
7806
|
})).sort((a, b) => {
|
|
6866
|
-
var
|
|
7807
|
+
var _a2, _b;
|
|
6867
7808
|
const primary = predicates[0];
|
|
6868
|
-
const aValue = (
|
|
7809
|
+
const aValue = (_a2 = this.resolveNumericPredicateValue(a, primary)) != null ? _a2 : 0;
|
|
6869
7810
|
const bValue = (_b = this.resolveNumericPredicateValue(b, primary)) != null ? _b : 0;
|
|
6870
7811
|
return primary.operator === "lt" || primary.operator === "lte" ? aValue - bValue : bValue - aValue;
|
|
6871
7812
|
});
|
|
@@ -6937,8 +7878,8 @@ ${context}`;
|
|
|
6937
7878
|
return Number.isFinite(numeric) ? numeric : null;
|
|
6938
7879
|
}
|
|
6939
7880
|
async retrieve(query, options) {
|
|
6940
|
-
var
|
|
6941
|
-
const ns = (
|
|
7881
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
7882
|
+
const ns = (_a2 = options.namespace) != null ? _a2 : this.config.projectId;
|
|
6942
7883
|
const topK = (_b = options.topK) != null ? _b : 5;
|
|
6943
7884
|
const cacheKey = `${ns}::${query}`;
|
|
6944
7885
|
let queryVector = this.embeddingCache.get(cacheKey);
|
|
@@ -6970,7 +7911,7 @@ ${context}`;
|
|
|
6970
7911
|
) : [];
|
|
6971
7912
|
const resolvedSources = [];
|
|
6972
7913
|
for (const source of sources) {
|
|
6973
|
-
const parentId = (
|
|
7914
|
+
const parentId = (_g2 = source.metadata) == null ? void 0 : _g2.parent_id;
|
|
6974
7915
|
if (parentId) {
|
|
6975
7916
|
console.log(`[Pipeline] Multi-Vector: Found child chunk. Parent ID: ${parentId}`);
|
|
6976
7917
|
resolvedSources.push(source);
|
|
@@ -7148,14 +8089,142 @@ var ProviderHealthCheck = class {
|
|
|
7148
8089
|
}
|
|
7149
8090
|
};
|
|
7150
8091
|
|
|
8092
|
+
// src/core/LicenseVerifier.ts
|
|
8093
|
+
import * as crypto2 from "crypto";
|
|
8094
|
+
var LicenseVerifier = class {
|
|
8095
|
+
/**
|
|
8096
|
+
* Decodes, verifies signature, and checks metadata of a license key.
|
|
8097
|
+
*
|
|
8098
|
+
* @param licenseKey - Base64url signed JWT license key.
|
|
8099
|
+
* @param currentProjectId - Project namespace ID.
|
|
8100
|
+
* @param publicKeyOverride - Optional override for unit/integration tests.
|
|
8101
|
+
*/
|
|
8102
|
+
static verify(licenseKey, currentProjectId, provider, publicKeyOverride) {
|
|
8103
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
8104
|
+
if (!licenseKey) {
|
|
8105
|
+
if (isProduction) {
|
|
8106
|
+
throw new ConfigurationException(
|
|
8107
|
+
"[Retrivora SDK] License key (licenseKey) is required in production environments."
|
|
8108
|
+
);
|
|
8109
|
+
}
|
|
8110
|
+
console.warn(
|
|
8111
|
+
`\x1B[33m[Retrivora SDK] WARNING: Running without a license key. This namespace (${currentProjectId}) is permitted for local development only.\x1B[0m`
|
|
8112
|
+
);
|
|
8113
|
+
return {
|
|
8114
|
+
projectId: currentProjectId,
|
|
8115
|
+
expiresAt: Math.floor(Date.now() / 1e3) + 86400,
|
|
8116
|
+
// Valid for 24h
|
|
8117
|
+
tier: "hobby"
|
|
8118
|
+
};
|
|
8119
|
+
}
|
|
8120
|
+
try {
|
|
8121
|
+
const parts = licenseKey.split(".");
|
|
8122
|
+
if (parts.length !== 3) {
|
|
8123
|
+
throw new Error("Malformed token structure (expected 3 parts).");
|
|
8124
|
+
}
|
|
8125
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
8126
|
+
const dataToVerify = `${headerB64}.${payloadB64}`;
|
|
8127
|
+
const publicKey = publicKeyOverride != null ? publicKeyOverride : this.PUBLIC_KEY;
|
|
8128
|
+
const signature = Buffer.from(signatureB64, "base64url");
|
|
8129
|
+
const data = Buffer.from(dataToVerify);
|
|
8130
|
+
const isValid = crypto2.verify(
|
|
8131
|
+
"sha256",
|
|
8132
|
+
data,
|
|
8133
|
+
publicKey,
|
|
8134
|
+
signature
|
|
8135
|
+
);
|
|
8136
|
+
if (!isValid) {
|
|
8137
|
+
throw new Error("Signature verification failed.");
|
|
8138
|
+
}
|
|
8139
|
+
const payload = JSON.parse(
|
|
8140
|
+
Buffer.from(payloadB64, "base64url").toString("utf8")
|
|
8141
|
+
);
|
|
8142
|
+
if (!payload.projectId) {
|
|
8143
|
+
throw new Error('License payload is missing "projectId".');
|
|
8144
|
+
}
|
|
8145
|
+
if (payload.projectId !== currentProjectId) {
|
|
8146
|
+
throw new Error(
|
|
8147
|
+
`Project ID mismatch. License is bound to project namespace "${payload.projectId}" but configuration has "${currentProjectId}".`
|
|
8148
|
+
);
|
|
8149
|
+
}
|
|
8150
|
+
if (!payload.expiresAt) {
|
|
8151
|
+
throw new Error('License payload is missing expiration ("expiresAt").');
|
|
8152
|
+
}
|
|
8153
|
+
const currentTimestampSec = Math.floor(Date.now() / 1e3);
|
|
8154
|
+
if (currentTimestampSec > payload.expiresAt) {
|
|
8155
|
+
throw new Error(
|
|
8156
|
+
`License key has expired. Expiration: ${new Date(
|
|
8157
|
+
payload.expiresAt * 1e3
|
|
8158
|
+
).toDateString()}`
|
|
8159
|
+
);
|
|
8160
|
+
}
|
|
8161
|
+
if (isProduction && provider) {
|
|
8162
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8163
|
+
const normalizedProvider = provider.toLowerCase();
|
|
8164
|
+
if (tier === "hobby") {
|
|
8165
|
+
const allowedHobby = ["postgresql", "pgvector", "supabase"];
|
|
8166
|
+
if (!allowedHobby.includes(normalizedProvider)) {
|
|
8167
|
+
throw new Error(
|
|
8168
|
+
`The database provider "${provider}" is not allowed on the Hobby tier. Hobby tier is restricted to PostgreSQL and Supabase. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8169
|
+
);
|
|
8170
|
+
}
|
|
8171
|
+
} else if (tier === "pro" || tier === "developer_pro" || tier === "premium" || tier === "growth") {
|
|
8172
|
+
const allowedPro = [
|
|
8173
|
+
"postgresql",
|
|
8174
|
+
"pgvector",
|
|
8175
|
+
"supabase",
|
|
8176
|
+
"pinecone",
|
|
8177
|
+
"qdrant",
|
|
8178
|
+
"mongodb",
|
|
8179
|
+
"milvus",
|
|
8180
|
+
"chroma",
|
|
8181
|
+
"chromadb"
|
|
8182
|
+
];
|
|
8183
|
+
if (!allowedPro.includes(normalizedProvider)) {
|
|
8184
|
+
throw new Error(
|
|
8185
|
+
`The database provider "${provider}" is not allowed on the Developer Pro tier. Please upgrade to an Enterprise plan.`
|
|
8186
|
+
);
|
|
8187
|
+
}
|
|
8188
|
+
}
|
|
8189
|
+
}
|
|
8190
|
+
return payload;
|
|
8191
|
+
} catch (err) {
|
|
8192
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
8193
|
+
throw new ConfigurationException(
|
|
8194
|
+
`[Retrivora SDK] License key validation failed: ${message}`
|
|
8195
|
+
);
|
|
8196
|
+
}
|
|
8197
|
+
}
|
|
8198
|
+
};
|
|
8199
|
+
// Retrivora's Public Key used to verify the license key signature.
|
|
8200
|
+
// In production, this matches the private key held by Retrivora SaaS.
|
|
8201
|
+
LicenseVerifier.PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
|
8202
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMieCkCBtTfByRNOserm
|
|
8203
|
+
XM4T0Am29JyNzB4XQPe+WJJ56CN73H1HLXx9n1ByFcxkEJ9po+SURj5DnvUXwEy+
|
|
8204
|
+
xstx33wDPpVmcMQe33j5CRYS0S4gICiNqIRN7XkTlJtrcXqrmh1/hdOAwfRbjO1T
|
|
8205
|
+
NVtORHwUwWfI/lBLyxUPGtKPed+0fQ7NtcW4o00JXxs3EjCB5BV9CbnXoTjQb/4h
|
|
8206
|
+
iwZof4l8rb7oaNzOsVg0RSyxsETX7Ex5sI0CjBz1p2mYp4oVhw/A/h8Ls7H0XzjC
|
|
8207
|
+
+Eb6BLtsytt5JHoSp0jExLlCpDmpys2L+kETcBVx+IqiXtdN1n6KbkksvEDUVzLI
|
|
8208
|
+
MwIDAQAB
|
|
8209
|
+
-----END PUBLIC KEY-----`;
|
|
8210
|
+
|
|
7151
8211
|
// src/core/VectorPlugin.ts
|
|
7152
8212
|
var VectorPlugin = class {
|
|
7153
8213
|
constructor(hostConfig) {
|
|
7154
|
-
|
|
7155
|
-
this.
|
|
8214
|
+
const resolvedConfig = ConfigResolver.resolve(hostConfig);
|
|
8215
|
+
this.config = resolvedConfig;
|
|
8216
|
+
this.validationPromise = (async () => {
|
|
8217
|
+
var _a2;
|
|
8218
|
+
await ConfigValidator.validateAndThrow(resolvedConfig);
|
|
8219
|
+
LicenseVerifier.verify(
|
|
8220
|
+
resolvedConfig.licenseKey,
|
|
8221
|
+
resolvedConfig.projectId,
|
|
8222
|
+
(_a2 = resolvedConfig.vectorDb) == null ? void 0 : _a2.provider
|
|
8223
|
+
);
|
|
8224
|
+
})();
|
|
7156
8225
|
this.validationPromise.catch(() => {
|
|
7157
8226
|
});
|
|
7158
|
-
this.pipeline = new Pipeline(
|
|
8227
|
+
this.pipeline = new Pipeline(resolvedConfig);
|
|
7159
8228
|
}
|
|
7160
8229
|
/**
|
|
7161
8230
|
* Get the current resolved configuration.
|
|
@@ -7284,8 +8353,8 @@ var DocumentParser = class {
|
|
|
7284
8353
|
* Extract text from a File or Buffer based on its type.
|
|
7285
8354
|
*/
|
|
7286
8355
|
static async parse(file, fileName, mimeType) {
|
|
7287
|
-
var
|
|
7288
|
-
const extension = (
|
|
8356
|
+
var _a2;
|
|
8357
|
+
const extension = (_a2 = fileName.split(".").pop()) == null ? void 0 : _a2.toLowerCase();
|
|
7289
8358
|
if (extension === "txt" || extension === "md" || mimeType === "text/plain" || mimeType === "text/markdown") {
|
|
7290
8359
|
return this.readAsText(file);
|
|
7291
8360
|
}
|
|
@@ -7337,7 +8406,496 @@ var DocumentParser = class {
|
|
|
7337
8406
|
}
|
|
7338
8407
|
};
|
|
7339
8408
|
|
|
8409
|
+
// src/core/DatabaseStorage.ts
|
|
8410
|
+
import * as fs from "fs";
|
|
8411
|
+
import * as path from "path";
|
|
8412
|
+
var DatabaseStorage = class {
|
|
8413
|
+
constructor(config) {
|
|
8414
|
+
// Dynamic PG Pool
|
|
8415
|
+
this.pgPool = null;
|
|
8416
|
+
// Dynamic MongoDB Client
|
|
8417
|
+
this.mongoClient = null;
|
|
8418
|
+
this.mongoDbName = "";
|
|
8419
|
+
// Filesystem fallback configuration
|
|
8420
|
+
this.fallbackDir = path.join(process.cwd(), ".retrivora");
|
|
8421
|
+
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
8422
|
+
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
8423
|
+
var _a2, _b, _c, _d, _e;
|
|
8424
|
+
this.config = config;
|
|
8425
|
+
this.provider = ((_a2 = config.vectorDb) == null ? void 0 : _a2.provider) || "fs";
|
|
8426
|
+
const rawHistoryTable = ((_c = (_b = config.rag) == null ? void 0 : _b.history) == null ? void 0 : _c.tableName) || "retrivora_history";
|
|
8427
|
+
const rawFeedbackTable = ((_e = (_d = config.rag) == null ? void 0 : _d.feedback) == null ? void 0 : _e.tableName) || "retrivora_feedback";
|
|
8428
|
+
this.historyTableName = rawHistoryTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8429
|
+
this.feedbackTableName = rawFeedbackTable.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
8430
|
+
}
|
|
8431
|
+
/**
|
|
8432
|
+
* Asserts the user is running a valid Premium/Enterprise license in production.
|
|
8433
|
+
* In non-production (development / test) environments this is a complete no-op —
|
|
8434
|
+
* all History and Feedback features are freely accessible for local development.
|
|
8435
|
+
*/
|
|
8436
|
+
checkPremiumSubscription() {
|
|
8437
|
+
if (process.env.NODE_ENV !== "production") {
|
|
8438
|
+
return;
|
|
8439
|
+
}
|
|
8440
|
+
if (!this.config.licenseKey) {
|
|
8441
|
+
throw new Error(
|
|
8442
|
+
"[Retrivora SDK] Chat History and Feedback features require a Premium or Enterprise license key in production."
|
|
8443
|
+
);
|
|
8444
|
+
}
|
|
8445
|
+
try {
|
|
8446
|
+
const payload = LicenseVerifier.verify(this.config.licenseKey, this.config.projectId);
|
|
8447
|
+
const tier = (payload.tier || "").toLowerCase();
|
|
8448
|
+
if (tier !== "premium" && tier !== "enterprise" && tier !== "growth" && tier !== "pro" && tier !== "developer_pro") {
|
|
8449
|
+
throw new Error(
|
|
8450
|
+
`[Retrivora SDK] Chat History and Feedback features are not available on the "${tier}" tier. Please upgrade to a Developer Pro or Enterprise plan.`
|
|
8451
|
+
);
|
|
8452
|
+
}
|
|
8453
|
+
} catch (err) {
|
|
8454
|
+
throw new Error(
|
|
8455
|
+
`[Retrivora SDK] Subscription check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
8456
|
+
);
|
|
8457
|
+
}
|
|
8458
|
+
}
|
|
8459
|
+
checkHistoryEnabled() {
|
|
8460
|
+
var _a2, _b;
|
|
8461
|
+
this.checkPremiumSubscription();
|
|
8462
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.history) == null ? void 0 : _b.enabled) === false) {
|
|
8463
|
+
throw new Error("[Retrivora SDK] Chat History is disabled in RagConfig.");
|
|
8464
|
+
}
|
|
8465
|
+
}
|
|
8466
|
+
checkFeedbackEnabled() {
|
|
8467
|
+
var _a2, _b;
|
|
8468
|
+
this.checkPremiumSubscription();
|
|
8469
|
+
if (((_b = (_a2 = this.config.rag) == null ? void 0 : _a2.feedback) == null ? void 0 : _b.enabled) === false) {
|
|
8470
|
+
throw new Error("[Retrivora SDK] User Feedback is disabled in RagConfig.");
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
8473
|
+
async getPGPool() {
|
|
8474
|
+
const globalKey = `__retrivora_pg_pool_${this.config.projectId}`;
|
|
8475
|
+
const _g2 = global;
|
|
8476
|
+
if (_g2[globalKey]) {
|
|
8477
|
+
this.pgPool = _g2[globalKey];
|
|
8478
|
+
return this.pgPool;
|
|
8479
|
+
}
|
|
8480
|
+
const opts = this.config.vectorDb.options;
|
|
8481
|
+
if (!opts.connectionString) {
|
|
8482
|
+
throw new Error("[DatabaseStorage] pg connectionString option is missing.");
|
|
8483
|
+
}
|
|
8484
|
+
const { Pool: Pool3 } = await import("pg");
|
|
8485
|
+
this.pgPool = new Pool3({ connectionString: opts.connectionString });
|
|
8486
|
+
_g2[globalKey] = this.pgPool;
|
|
8487
|
+
const client = await this.pgPool.connect();
|
|
8488
|
+
try {
|
|
8489
|
+
await client.query(`
|
|
8490
|
+
CREATE TABLE IF NOT EXISTS ${this.historyTableName} (
|
|
8491
|
+
id TEXT PRIMARY KEY,
|
|
8492
|
+
session_id TEXT NOT NULL,
|
|
8493
|
+
role TEXT NOT NULL,
|
|
8494
|
+
content TEXT NOT NULL,
|
|
8495
|
+
sources JSONB,
|
|
8496
|
+
ui_transformation JSONB,
|
|
8497
|
+
trace JSONB,
|
|
8498
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8499
|
+
)
|
|
8500
|
+
`);
|
|
8501
|
+
await client.query(`
|
|
8502
|
+
CREATE TABLE IF NOT EXISTS ${this.feedbackTableName} (
|
|
8503
|
+
id TEXT PRIMARY KEY,
|
|
8504
|
+
message_id TEXT NOT NULL UNIQUE,
|
|
8505
|
+
session_id TEXT NOT NULL,
|
|
8506
|
+
rating TEXT NOT NULL,
|
|
8507
|
+
comment TEXT,
|
|
8508
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
|
|
8509
|
+
)
|
|
8510
|
+
`);
|
|
8511
|
+
} finally {
|
|
8512
|
+
client.release();
|
|
8513
|
+
}
|
|
8514
|
+
return this.pgPool;
|
|
8515
|
+
}
|
|
8516
|
+
async getMongoClient() {
|
|
8517
|
+
const globalKey = `__retrivora_mongo_client_${this.config.projectId}`;
|
|
8518
|
+
const _g2 = global;
|
|
8519
|
+
if (_g2[globalKey]) {
|
|
8520
|
+
this.mongoClient = _g2[globalKey];
|
|
8521
|
+
this.mongoDbName = this.config.vectorDb.options.database;
|
|
8522
|
+
return this.mongoClient;
|
|
8523
|
+
}
|
|
8524
|
+
const opts = this.config.vectorDb.options;
|
|
8525
|
+
if (!opts.uri || !opts.database) {
|
|
8526
|
+
throw new Error("[DatabaseStorage] mongo uri and database options are missing.");
|
|
8527
|
+
}
|
|
8528
|
+
const { MongoClient: MongoClient2 } = await import("mongodb");
|
|
8529
|
+
this.mongoClient = new MongoClient2(opts.uri);
|
|
8530
|
+
await this.mongoClient.connect();
|
|
8531
|
+
_g2[globalKey] = this.mongoClient;
|
|
8532
|
+
this.mongoDbName = opts.database;
|
|
8533
|
+
return this.mongoClient;
|
|
8534
|
+
}
|
|
8535
|
+
getMongoDb() {
|
|
8536
|
+
return this.mongoClient.db(this.mongoDbName);
|
|
8537
|
+
}
|
|
8538
|
+
// Helper for FS fallback reads
|
|
8539
|
+
readLocalFile(filePath) {
|
|
8540
|
+
if (!fs.existsSync(filePath)) return [];
|
|
8541
|
+
try {
|
|
8542
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
8543
|
+
return JSON.parse(raw) || [];
|
|
8544
|
+
} catch (e) {
|
|
8545
|
+
return [];
|
|
8546
|
+
}
|
|
8547
|
+
}
|
|
8548
|
+
// Helper for FS fallback writes
|
|
8549
|
+
writeLocalFile(filePath, data) {
|
|
8550
|
+
if (!fs.existsSync(this.fallbackDir)) {
|
|
8551
|
+
fs.mkdirSync(this.fallbackDir, { recursive: true });
|
|
8552
|
+
}
|
|
8553
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
8554
|
+
}
|
|
8555
|
+
// ─── Message History Operations ──────────────────────────────────────────
|
|
8556
|
+
async saveMessage(sessionId, message) {
|
|
8557
|
+
this.checkHistoryEnabled();
|
|
8558
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8559
|
+
const msgId = message.id || `msg_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8560
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8561
|
+
const pool = await this.getPGPool();
|
|
8562
|
+
await pool.query(
|
|
8563
|
+
`INSERT INTO ${this.historyTableName} (id, session_id, role, content, sources, ui_transformation, trace, created_at)
|
|
8564
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
8565
|
+
ON CONFLICT (id) DO UPDATE
|
|
8566
|
+
SET content = EXCLUDED.content, sources = EXCLUDED.sources, ui_transformation = EXCLUDED.ui_transformation, trace = EXCLUDED.trace`,
|
|
8567
|
+
[
|
|
8568
|
+
msgId,
|
|
8569
|
+
sessionId,
|
|
8570
|
+
message.role,
|
|
8571
|
+
message.content,
|
|
8572
|
+
message.sources ? JSON.stringify(message.sources) : null,
|
|
8573
|
+
message.uiTransformation ? JSON.stringify(message.uiTransformation) : null,
|
|
8574
|
+
message.trace ? JSON.stringify(message.trace) : null,
|
|
8575
|
+
createdAt
|
|
8576
|
+
]
|
|
8577
|
+
);
|
|
8578
|
+
} else if (this.provider === "mongodb") {
|
|
8579
|
+
await this.getMongoClient();
|
|
8580
|
+
const db = this.getMongoDb();
|
|
8581
|
+
const col = db.collection(this.historyTableName);
|
|
8582
|
+
await col.updateOne(
|
|
8583
|
+
{ id: msgId },
|
|
8584
|
+
{
|
|
8585
|
+
$set: {
|
|
8586
|
+
id: msgId,
|
|
8587
|
+
session_id: sessionId,
|
|
8588
|
+
role: message.role,
|
|
8589
|
+
content: message.content,
|
|
8590
|
+
sources: message.sources || null,
|
|
8591
|
+
ui_transformation: message.uiTransformation || null,
|
|
8592
|
+
trace: message.trace || null,
|
|
8593
|
+
created_at: createdAt
|
|
8594
|
+
}
|
|
8595
|
+
},
|
|
8596
|
+
{ upsert: true }
|
|
8597
|
+
);
|
|
8598
|
+
} else {
|
|
8599
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8600
|
+
const index = history.findIndex((h) => h.id === msgId);
|
|
8601
|
+
const item = {
|
|
8602
|
+
id: msgId,
|
|
8603
|
+
session_id: sessionId,
|
|
8604
|
+
role: message.role,
|
|
8605
|
+
content: message.content,
|
|
8606
|
+
sources: message.sources || null,
|
|
8607
|
+
ui_transformation: message.uiTransformation || null,
|
|
8608
|
+
trace: message.trace || null,
|
|
8609
|
+
created_at: createdAt
|
|
8610
|
+
};
|
|
8611
|
+
if (index !== -1) {
|
|
8612
|
+
history[index] = item;
|
|
8613
|
+
} else {
|
|
8614
|
+
history.push(item);
|
|
8615
|
+
}
|
|
8616
|
+
this.writeLocalFile(this.historyFile, history);
|
|
8617
|
+
}
|
|
8618
|
+
}
|
|
8619
|
+
async getHistory(sessionId) {
|
|
8620
|
+
this.checkHistoryEnabled();
|
|
8621
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8622
|
+
const pool = await this.getPGPool();
|
|
8623
|
+
const res = await pool.query(
|
|
8624
|
+
`SELECT id, role, content, sources, ui_transformation as "uiTransformation", trace, created_at as "createdAt"
|
|
8625
|
+
FROM ${this.historyTableName}
|
|
8626
|
+
WHERE session_id = $1
|
|
8627
|
+
ORDER BY created_at ASC`,
|
|
8628
|
+
[sessionId]
|
|
8629
|
+
);
|
|
8630
|
+
return res.rows;
|
|
8631
|
+
} else if (this.provider === "mongodb") {
|
|
8632
|
+
await this.getMongoClient();
|
|
8633
|
+
const db = this.getMongoDb();
|
|
8634
|
+
const col = db.collection(this.historyTableName);
|
|
8635
|
+
const items = await col.find({ session_id: sessionId }).sort({ created_at: 1 }).toArray();
|
|
8636
|
+
return items.map((item) => ({
|
|
8637
|
+
id: item.id,
|
|
8638
|
+
role: item.role,
|
|
8639
|
+
content: item.content,
|
|
8640
|
+
sources: item.sources,
|
|
8641
|
+
uiTransformation: item.ui_transformation,
|
|
8642
|
+
trace: item.trace,
|
|
8643
|
+
createdAt: item.created_at
|
|
8644
|
+
}));
|
|
8645
|
+
} else {
|
|
8646
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8647
|
+
return history.filter((h) => h.session_id === sessionId).sort((a, b) => new Date(a.created_at).getTime() - new Date(b.created_at).getTime());
|
|
8648
|
+
}
|
|
8649
|
+
}
|
|
8650
|
+
async clearHistory(sessionId) {
|
|
8651
|
+
this.checkHistoryEnabled();
|
|
8652
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8653
|
+
const pool = await this.getPGPool();
|
|
8654
|
+
await pool.query(`DELETE FROM ${this.historyTableName} WHERE session_id = $1`, [sessionId]);
|
|
8655
|
+
await pool.query(`DELETE FROM ${this.feedbackTableName} WHERE session_id = $1`, [sessionId]);
|
|
8656
|
+
} else if (this.provider === "mongodb") {
|
|
8657
|
+
await this.getMongoClient();
|
|
8658
|
+
const db = this.getMongoDb();
|
|
8659
|
+
await db.collection(this.historyTableName).deleteMany({ session_id: sessionId });
|
|
8660
|
+
await db.collection(this.feedbackTableName).deleteMany({ session_id: sessionId });
|
|
8661
|
+
} else {
|
|
8662
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8663
|
+
const filteredHistory = history.filter((h) => h.session_id !== sessionId);
|
|
8664
|
+
this.writeLocalFile(this.historyFile, filteredHistory);
|
|
8665
|
+
const feedback = this.readLocalFile(this.feedbackFile);
|
|
8666
|
+
const filteredFeedback = feedback.filter((f) => f.session_id !== sessionId);
|
|
8667
|
+
this.writeLocalFile(this.feedbackFile, filteredFeedback);
|
|
8668
|
+
}
|
|
8669
|
+
}
|
|
8670
|
+
async listSessions() {
|
|
8671
|
+
this.checkHistoryEnabled();
|
|
8672
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8673
|
+
const pool = await this.getPGPool();
|
|
8674
|
+
const res = await pool.query(`SELECT DISTINCT session_id FROM ${this.historyTableName}`);
|
|
8675
|
+
return res.rows.map((r) => r.session_id);
|
|
8676
|
+
} else if (this.provider === "mongodb") {
|
|
8677
|
+
await this.getMongoClient();
|
|
8678
|
+
const db = this.getMongoDb();
|
|
8679
|
+
return db.collection(this.historyTableName).distinct("session_id");
|
|
8680
|
+
} else {
|
|
8681
|
+
const history = this.readLocalFile(this.historyFile);
|
|
8682
|
+
const sessions = new Set(history.map((h) => h.session_id));
|
|
8683
|
+
return Array.from(sessions);
|
|
8684
|
+
}
|
|
8685
|
+
}
|
|
8686
|
+
// ─── Feedback Operations ──────────────────────────────────────────────────
|
|
8687
|
+
async saveFeedback(feedback) {
|
|
8688
|
+
this.checkFeedbackEnabled();
|
|
8689
|
+
const id = `fb_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8690
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8691
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8692
|
+
const pool = await this.getPGPool();
|
|
8693
|
+
await pool.query(
|
|
8694
|
+
`INSERT INTO ${this.feedbackTableName} (id, message_id, session_id, rating, comment, created_at)
|
|
8695
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
8696
|
+
ON CONFLICT (message_id) DO UPDATE
|
|
8697
|
+
SET rating = EXCLUDED.rating, comment = EXCLUDED.comment`,
|
|
8698
|
+
[id, feedback.messageId, feedback.sessionId, feedback.rating, feedback.comment || null, createdAt]
|
|
8699
|
+
);
|
|
8700
|
+
} else if (this.provider === "mongodb") {
|
|
8701
|
+
await this.getMongoClient();
|
|
8702
|
+
const db = this.getMongoDb();
|
|
8703
|
+
const col = db.collection(this.feedbackTableName);
|
|
8704
|
+
await col.updateOne(
|
|
8705
|
+
{ message_id: feedback.messageId },
|
|
8706
|
+
{
|
|
8707
|
+
$set: {
|
|
8708
|
+
id,
|
|
8709
|
+
message_id: feedback.messageId,
|
|
8710
|
+
session_id: feedback.sessionId,
|
|
8711
|
+
rating: feedback.rating,
|
|
8712
|
+
comment: feedback.comment || null,
|
|
8713
|
+
created_at: createdAt
|
|
8714
|
+
}
|
|
8715
|
+
},
|
|
8716
|
+
{ upsert: true }
|
|
8717
|
+
);
|
|
8718
|
+
} else {
|
|
8719
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8720
|
+
const index = list.findIndex((f) => f.message_id === feedback.messageId);
|
|
8721
|
+
const item = {
|
|
8722
|
+
id,
|
|
8723
|
+
message_id: feedback.messageId,
|
|
8724
|
+
session_id: feedback.sessionId,
|
|
8725
|
+
rating: feedback.rating,
|
|
8726
|
+
comment: feedback.comment || null,
|
|
8727
|
+
created_at: createdAt
|
|
8728
|
+
};
|
|
8729
|
+
if (index !== -1) {
|
|
8730
|
+
list[index] = item;
|
|
8731
|
+
} else {
|
|
8732
|
+
list.push(item);
|
|
8733
|
+
}
|
|
8734
|
+
this.writeLocalFile(this.feedbackFile, list);
|
|
8735
|
+
}
|
|
8736
|
+
}
|
|
8737
|
+
async getFeedback(messageId) {
|
|
8738
|
+
this.checkFeedbackEnabled();
|
|
8739
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8740
|
+
const pool = await this.getPGPool();
|
|
8741
|
+
const res = await pool.query(
|
|
8742
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8743
|
+
FROM ${this.feedbackTableName}
|
|
8744
|
+
WHERE message_id = $1`,
|
|
8745
|
+
[messageId]
|
|
8746
|
+
);
|
|
8747
|
+
return res.rows[0] || null;
|
|
8748
|
+
} else if (this.provider === "mongodb") {
|
|
8749
|
+
await this.getMongoClient();
|
|
8750
|
+
const db = this.getMongoDb();
|
|
8751
|
+
const col = db.collection(this.feedbackTableName);
|
|
8752
|
+
const item = await col.findOne({ message_id: messageId });
|
|
8753
|
+
if (!item) return null;
|
|
8754
|
+
return {
|
|
8755
|
+
id: item.id,
|
|
8756
|
+
messageId: item.message_id,
|
|
8757
|
+
sessionId: item.session_id,
|
|
8758
|
+
rating: item.rating,
|
|
8759
|
+
comment: item.comment,
|
|
8760
|
+
createdAt: item.created_at
|
|
8761
|
+
};
|
|
8762
|
+
} else {
|
|
8763
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8764
|
+
return list.find((f) => f.message_id === messageId) || null;
|
|
8765
|
+
}
|
|
8766
|
+
}
|
|
8767
|
+
async listFeedback() {
|
|
8768
|
+
this.checkFeedbackEnabled();
|
|
8769
|
+
if (this.provider === "postgresql" || this.provider === "pgvector") {
|
|
8770
|
+
const pool = await this.getPGPool();
|
|
8771
|
+
const res = await pool.query(
|
|
8772
|
+
`SELECT id, message_id as "messageId", session_id as "sessionId", rating, comment, created_at as "createdAt"
|
|
8773
|
+
FROM ${this.feedbackTableName}
|
|
8774
|
+
ORDER BY created_at DESC`
|
|
8775
|
+
);
|
|
8776
|
+
return res.rows;
|
|
8777
|
+
} else if (this.provider === "mongodb") {
|
|
8778
|
+
await this.getMongoClient();
|
|
8779
|
+
const db = this.getMongoDb();
|
|
8780
|
+
const col = db.collection(this.feedbackTableName);
|
|
8781
|
+
const items = await col.find({}).sort({ created_at: -1 }).toArray();
|
|
8782
|
+
return items.map((item) => ({
|
|
8783
|
+
id: item.id,
|
|
8784
|
+
messageId: item.message_id,
|
|
8785
|
+
sessionId: item.session_id,
|
|
8786
|
+
rating: item.rating,
|
|
8787
|
+
comment: item.comment,
|
|
8788
|
+
createdAt: item.created_at
|
|
8789
|
+
}));
|
|
8790
|
+
} else {
|
|
8791
|
+
const list = this.readLocalFile(this.feedbackFile);
|
|
8792
|
+
return [...list].sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
|
8793
|
+
}
|
|
8794
|
+
}
|
|
8795
|
+
async disconnect() {
|
|
8796
|
+
if (this.pgPool) {
|
|
8797
|
+
await this.pgPool.end();
|
|
8798
|
+
this.pgPool = null;
|
|
8799
|
+
}
|
|
8800
|
+
if (this.mongoClient) {
|
|
8801
|
+
await this.mongoClient.close();
|
|
8802
|
+
this.mongoClient = null;
|
|
8803
|
+
}
|
|
8804
|
+
}
|
|
8805
|
+
};
|
|
8806
|
+
|
|
7340
8807
|
// src/handlers/index.ts
|
|
8808
|
+
async function checkAuth(req, onAuthorize) {
|
|
8809
|
+
if (!onAuthorize) return null;
|
|
8810
|
+
try {
|
|
8811
|
+
const res = await onAuthorize(req);
|
|
8812
|
+
if (res === false) {
|
|
8813
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
8814
|
+
}
|
|
8815
|
+
if (res instanceof Response) {
|
|
8816
|
+
return res;
|
|
8817
|
+
}
|
|
8818
|
+
return null;
|
|
8819
|
+
} catch (err) {
|
|
8820
|
+
const msg = err instanceof Error ? err.message : "Authorization check failed";
|
|
8821
|
+
return NextResponse.json({ error: msg }, { status: 401 });
|
|
8822
|
+
}
|
|
8823
|
+
}
|
|
8824
|
+
var RateLimiter = class {
|
|
8825
|
+
constructor(windowMs = 6e4, max = 30) {
|
|
8826
|
+
this.hits = /* @__PURE__ */ new Map();
|
|
8827
|
+
this.windowMs = windowMs;
|
|
8828
|
+
this.max = max;
|
|
8829
|
+
}
|
|
8830
|
+
/** Returns true if the request should be allowed, false if rate-limited. */
|
|
8831
|
+
allow(key) {
|
|
8832
|
+
const now = Date.now();
|
|
8833
|
+
const cutoff = now - this.windowMs;
|
|
8834
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
8835
|
+
existing.push(now);
|
|
8836
|
+
this.hits.set(key, existing);
|
|
8837
|
+
if (this.hits.size > 5e3) {
|
|
8838
|
+
for (const [k, timestamps] of this.hits.entries()) {
|
|
8839
|
+
if (timestamps.every((t) => t <= cutoff)) this.hits.delete(k);
|
|
8840
|
+
}
|
|
8841
|
+
}
|
|
8842
|
+
return existing.length <= this.max;
|
|
8843
|
+
}
|
|
8844
|
+
retryAfterSec(key) {
|
|
8845
|
+
const now = Date.now();
|
|
8846
|
+
const cutoff = now - this.windowMs;
|
|
8847
|
+
const existing = (this.hits.get(key) || []).filter((t) => t > cutoff);
|
|
8848
|
+
if (existing.length === 0) return 0;
|
|
8849
|
+
return Math.ceil((existing[0] + this.windowMs - now) / 1e3);
|
|
8850
|
+
}
|
|
8851
|
+
};
|
|
8852
|
+
var _g = global;
|
|
8853
|
+
var _a;
|
|
8854
|
+
var rateLimiter = (_a = _g.__retrivoraRateLimiter) != null ? _a : _g.__retrivoraRateLimiter = new RateLimiter(6e4, 30);
|
|
8855
|
+
function getRateLimitKey(req) {
|
|
8856
|
+
var _a2, _b;
|
|
8857
|
+
const ip = ((_b = (_a2 = req.headers.get("x-forwarded-for")) == null ? void 0 : _a2.split(",")[0]) == null ? void 0 : _b.trim()) || req.headers.get("x-real-ip") || "127.0.0.1";
|
|
8858
|
+
return `ip:${ip}`;
|
|
8859
|
+
}
|
|
8860
|
+
function checkRateLimit(req) {
|
|
8861
|
+
const key = getRateLimitKey(req);
|
|
8862
|
+
if (!rateLimiter.allow(key)) {
|
|
8863
|
+
const retryAfter = rateLimiter.retryAfterSec(key);
|
|
8864
|
+
return new Response(
|
|
8865
|
+
JSON.stringify({ error: { code: "RATE_LIMITED", message: "Too many requests. Please slow down." } }),
|
|
8866
|
+
{
|
|
8867
|
+
status: 429,
|
|
8868
|
+
headers: {
|
|
8869
|
+
"Content-Type": "application/json",
|
|
8870
|
+
"Retry-After": String(retryAfter),
|
|
8871
|
+
"X-RateLimit-Limit": "30",
|
|
8872
|
+
"X-RateLimit-Window": "60"
|
|
8873
|
+
}
|
|
8874
|
+
}
|
|
8875
|
+
);
|
|
8876
|
+
}
|
|
8877
|
+
return null;
|
|
8878
|
+
}
|
|
8879
|
+
var MAX_MESSAGE_LENGTH = 8e3;
|
|
8880
|
+
function sanitizeInput(raw) {
|
|
8881
|
+
const stripped = raw.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
|
|
8882
|
+
const trimmed = stripped.trim();
|
|
8883
|
+
if (!trimmed) {
|
|
8884
|
+
return { ok: false, error: "message must not be empty" };
|
|
8885
|
+
}
|
|
8886
|
+
if (trimmed.length > MAX_MESSAGE_LENGTH) {
|
|
8887
|
+
return { ok: false, error: `message must be \u2264 ${MAX_MESSAGE_LENGTH} characters` };
|
|
8888
|
+
}
|
|
8889
|
+
return { ok: true, value: trimmed };
|
|
8890
|
+
}
|
|
8891
|
+
function getOrCreatePlugin(configOrPlugin) {
|
|
8892
|
+
if (configOrPlugin instanceof VectorPlugin) return configOrPlugin;
|
|
8893
|
+
const cacheKey = "__retrivoraPlugin_" + JSON.stringify(configOrPlugin != null ? configOrPlugin : {}).slice(0, 64);
|
|
8894
|
+
if (!_g[cacheKey]) {
|
|
8895
|
+
_g[cacheKey] = new VectorPlugin(configOrPlugin);
|
|
8896
|
+
}
|
|
8897
|
+
return _g[cacheKey];
|
|
8898
|
+
}
|
|
7341
8899
|
function sseFrame(payload) {
|
|
7342
8900
|
return `data: ${JSON.stringify(payload)}
|
|
7343
8901
|
|
|
@@ -7375,47 +8933,88 @@ var SSE_HEADERS = {
|
|
|
7375
8933
|
"X-Accel-Buffering": "no"
|
|
7376
8934
|
// Disable Nginx buffering for streaming
|
|
7377
8935
|
};
|
|
7378
|
-
function createChatHandler(configOrPlugin) {
|
|
7379
|
-
const plugin =
|
|
8936
|
+
function createChatHandler(configOrPlugin, options) {
|
|
8937
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
8938
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
8939
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7380
8940
|
return async function POST(req) {
|
|
8941
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
8942
|
+
if (authResult) return authResult;
|
|
8943
|
+
const rateLimited = checkRateLimit(req);
|
|
8944
|
+
if (rateLimited) return rateLimited;
|
|
7381
8945
|
try {
|
|
7382
8946
|
const body = await req.json();
|
|
7383
|
-
const { message, history = [], namespace } = body;
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
8947
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
8948
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
8949
|
+
if (!sanitized.ok) {
|
|
8950
|
+
return NextResponse.json({ error: { code: "INVALID_INPUT", message: sanitized.error } }, { status: 400 });
|
|
8951
|
+
}
|
|
8952
|
+
const message = sanitized.value;
|
|
8953
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8954
|
+
await storage.saveMessage(sessionId, {
|
|
8955
|
+
id: userMsgId,
|
|
8956
|
+
role: "user",
|
|
8957
|
+
content: message
|
|
8958
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save user message:", err));
|
|
7387
8959
|
const result = await plugin.chat(message, history, namespace);
|
|
7388
|
-
|
|
8960
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
8961
|
+
await storage.saveMessage(sessionId, {
|
|
8962
|
+
id: assistantMsgId,
|
|
8963
|
+
role: "assistant",
|
|
8964
|
+
content: result.reply,
|
|
8965
|
+
sources: result.sources,
|
|
8966
|
+
uiTransformation: result.ui_transformation,
|
|
8967
|
+
trace: result.trace
|
|
8968
|
+
}).catch((err) => console.warn("[createChatHandler] Failed to save assistant message:", err));
|
|
8969
|
+
return NextResponse.json(__spreadProps(__spreadValues({}, result), {
|
|
8970
|
+
messageId: assistantMsgId,
|
|
8971
|
+
userMessageId: userMsgId
|
|
8972
|
+
}));
|
|
7389
8973
|
} catch (err) {
|
|
7390
8974
|
const message = err instanceof Error ? err.message : "Internal server error";
|
|
7391
8975
|
return NextResponse.json({ error: message }, { status: 500 });
|
|
7392
8976
|
}
|
|
7393
8977
|
};
|
|
7394
8978
|
}
|
|
7395
|
-
function createStreamHandler(configOrPlugin) {
|
|
7396
|
-
const plugin =
|
|
8979
|
+
function createStreamHandler(configOrPlugin, options) {
|
|
8980
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
8981
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
8982
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7397
8983
|
return async function POST(req) {
|
|
8984
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
8985
|
+
if (authResult) return authResult;
|
|
8986
|
+
const rateLimited = checkRateLimit(req);
|
|
8987
|
+
if (rateLimited) return rateLimited;
|
|
7398
8988
|
let body;
|
|
7399
8989
|
try {
|
|
7400
8990
|
body = await req.json();
|
|
7401
8991
|
} catch (e) {
|
|
7402
|
-
return new Response(JSON.stringify({ error: "Invalid JSON body" }), {
|
|
8992
|
+
return new Response(JSON.stringify({ error: { code: "INVALID_JSON", message: "Invalid JSON body" } }), {
|
|
7403
8993
|
status: 400,
|
|
7404
8994
|
headers: { "Content-Type": "application/json" }
|
|
7405
8995
|
});
|
|
7406
8996
|
}
|
|
7407
|
-
const { message, history = [], namespace } = body;
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
8997
|
+
const { message: rawMessage, history = [], namespace, sessionId = "default", messageId, userMessageId } = body;
|
|
8998
|
+
const sanitized = sanitizeInput(rawMessage != null ? rawMessage : "");
|
|
8999
|
+
if (!sanitized.ok) {
|
|
9000
|
+
return new Response(
|
|
9001
|
+
JSON.stringify({ error: { code: "INVALID_INPUT", message: sanitized.error } }),
|
|
9002
|
+
{ status: 400, headers: { "Content-Type": "application/json" } }
|
|
9003
|
+
);
|
|
7413
9004
|
}
|
|
9005
|
+
const message = sanitized.value;
|
|
9006
|
+
const userMsgId = userMessageId || `user_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
9007
|
+
await storage.saveMessage(sessionId, {
|
|
9008
|
+
id: userMsgId,
|
|
9009
|
+
role: "user",
|
|
9010
|
+
content: message
|
|
9011
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save user message:", err));
|
|
9012
|
+
const assistantMsgId = messageId || `assistant_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`;
|
|
7414
9013
|
const encoder = new TextEncoder();
|
|
7415
9014
|
let isActive = true;
|
|
7416
9015
|
const stream = new ReadableStream({
|
|
7417
9016
|
async start(controller) {
|
|
7418
|
-
var
|
|
9017
|
+
var _a2;
|
|
7419
9018
|
const enqueue = (text) => {
|
|
7420
9019
|
if (!isActive) return;
|
|
7421
9020
|
try {
|
|
@@ -7426,11 +9025,13 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7426
9025
|
};
|
|
7427
9026
|
try {
|
|
7428
9027
|
const pipelineStream = plugin.chatStream(message, history, namespace);
|
|
9028
|
+
let fullReply = "";
|
|
7429
9029
|
try {
|
|
7430
9030
|
for (var iter = __forAwait(pipelineStream), more, temp, error; more = !(temp = await iter.next()).done; more = false) {
|
|
7431
9031
|
const chunk = temp.value;
|
|
7432
9032
|
if (!isActive) break;
|
|
7433
9033
|
if (typeof chunk === "string") {
|
|
9034
|
+
fullReply += chunk;
|
|
7434
9035
|
enqueue(sseTextFrame(chunk));
|
|
7435
9036
|
} else if (chunk && typeof chunk === "object" && "type" in chunk && chunk.type === "thinking") {
|
|
7436
9037
|
enqueue(`data: ${JSON.stringify(chunk)}
|
|
@@ -7443,9 +9044,10 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7443
9044
|
if (responseChunk == null ? void 0 : responseChunk.trace) {
|
|
7444
9045
|
enqueue(sseObservabilityFrame(responseChunk.trace));
|
|
7445
9046
|
}
|
|
9047
|
+
let uiTransformation = responseChunk == null ? void 0 : responseChunk.ui_transformation;
|
|
7446
9048
|
if (sources.length > 0) {
|
|
7447
9049
|
try {
|
|
7448
|
-
|
|
9050
|
+
uiTransformation = (_a2 = responseChunk == null ? void 0 : responseChunk.ui_transformation) != null ? _a2 : UITransformer.transform(message, sources, plugin.getConfig());
|
|
7449
9051
|
if (uiTransformation) {
|
|
7450
9052
|
enqueue(sseUIFrame(uiTransformation));
|
|
7451
9053
|
}
|
|
@@ -7453,11 +9055,22 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7453
9055
|
console.warn("[createStreamHandler] UI transformation warning:", transformError);
|
|
7454
9056
|
try {
|
|
7455
9057
|
const fallback = UITransformer.transform(message, sources, plugin.getConfig());
|
|
7456
|
-
if (fallback)
|
|
9058
|
+
if (fallback) {
|
|
9059
|
+
uiTransformation = fallback;
|
|
9060
|
+
enqueue(sseUIFrame(fallback));
|
|
9061
|
+
}
|
|
7457
9062
|
} catch (e) {
|
|
7458
9063
|
}
|
|
7459
9064
|
}
|
|
7460
9065
|
}
|
|
9066
|
+
await storage.saveMessage(sessionId, {
|
|
9067
|
+
id: assistantMsgId,
|
|
9068
|
+
role: "assistant",
|
|
9069
|
+
content: fullReply,
|
|
9070
|
+
sources,
|
|
9071
|
+
uiTransformation,
|
|
9072
|
+
trace: responseChunk == null ? void 0 : responseChunk.trace
|
|
9073
|
+
}).catch((err) => console.warn("[createStreamHandler] Failed to save assistant message:", err));
|
|
7461
9074
|
}
|
|
7462
9075
|
}
|
|
7463
9076
|
} catch (temp) {
|
|
@@ -7494,12 +9107,15 @@ function createStreamHandler(configOrPlugin) {
|
|
|
7494
9107
|
console.log("[createStreamHandler] Stream connection closed by client:", reason);
|
|
7495
9108
|
}
|
|
7496
9109
|
});
|
|
7497
|
-
return new Response(stream, { headers: SSE_HEADERS });
|
|
9110
|
+
return new Response(stream, { headers: __spreadProps(__spreadValues({}, SSE_HEADERS), { "x-message-id": assistantMsgId, "x-user-message-id": userMsgId }) });
|
|
7498
9111
|
};
|
|
7499
9112
|
}
|
|
7500
|
-
function createIngestHandler(configOrPlugin) {
|
|
7501
|
-
const plugin =
|
|
9113
|
+
function createIngestHandler(configOrPlugin, options) {
|
|
9114
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9115
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7502
9116
|
return async function POST(req) {
|
|
9117
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9118
|
+
if (authResult) return authResult;
|
|
7503
9119
|
try {
|
|
7504
9120
|
const body = await req.json();
|
|
7505
9121
|
const { documents, namespace } = body;
|
|
@@ -7514,9 +9130,14 @@ function createIngestHandler(configOrPlugin) {
|
|
|
7514
9130
|
}
|
|
7515
9131
|
};
|
|
7516
9132
|
}
|
|
7517
|
-
function createHealthHandler(configOrPlugin) {
|
|
7518
|
-
const plugin =
|
|
7519
|
-
|
|
9133
|
+
function createHealthHandler(configOrPlugin, options) {
|
|
9134
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9135
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9136
|
+
return async function GET(req) {
|
|
9137
|
+
if (req) {
|
|
9138
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9139
|
+
if (authResult) return authResult;
|
|
9140
|
+
}
|
|
7520
9141
|
try {
|
|
7521
9142
|
const health = await plugin.checkHealth();
|
|
7522
9143
|
const status = health.allHealthy ? "ok" : "degraded";
|
|
@@ -7531,9 +9152,12 @@ function createHealthHandler(configOrPlugin) {
|
|
|
7531
9152
|
}
|
|
7532
9153
|
};
|
|
7533
9154
|
}
|
|
7534
|
-
function createUploadHandler(configOrPlugin) {
|
|
7535
|
-
const plugin =
|
|
9155
|
+
function createUploadHandler(configOrPlugin, options) {
|
|
9156
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9157
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7536
9158
|
return async function POST(req) {
|
|
9159
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9160
|
+
if (authResult) return authResult;
|
|
7537
9161
|
try {
|
|
7538
9162
|
const formData = await req.formData();
|
|
7539
9163
|
const files = formData.getAll("files");
|
|
@@ -7607,9 +9231,12 @@ function createUploadHandler(configOrPlugin) {
|
|
|
7607
9231
|
}
|
|
7608
9232
|
};
|
|
7609
9233
|
}
|
|
7610
|
-
function createSuggestionsHandler(configOrPlugin) {
|
|
7611
|
-
const plugin =
|
|
9234
|
+
function createSuggestionsHandler(configOrPlugin, options) {
|
|
9235
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9236
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
7612
9237
|
return async function POST(req) {
|
|
9238
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9239
|
+
if (authResult) return authResult;
|
|
7613
9240
|
try {
|
|
7614
9241
|
const body = await req.json();
|
|
7615
9242
|
const { query, namespace } = body;
|
|
@@ -7624,13 +9251,108 @@ function createSuggestionsHandler(configOrPlugin) {
|
|
|
7624
9251
|
}
|
|
7625
9252
|
};
|
|
7626
9253
|
}
|
|
7627
|
-
function
|
|
7628
|
-
const plugin =
|
|
7629
|
-
const
|
|
7630
|
-
const
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
9254
|
+
function createHistoryHandler(configOrPlugin, options) {
|
|
9255
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9256
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9257
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9258
|
+
return async function handler(req) {
|
|
9259
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9260
|
+
if (authResult) return authResult;
|
|
9261
|
+
const url = new URL(req.url);
|
|
9262
|
+
const sessionId = url.searchParams.get("sessionId") || "default";
|
|
9263
|
+
if (req.method === "GET") {
|
|
9264
|
+
try {
|
|
9265
|
+
const history = await storage.getHistory(sessionId);
|
|
9266
|
+
return NextResponse.json({ history });
|
|
9267
|
+
} catch (err) {
|
|
9268
|
+
const message = err instanceof Error ? err.message : "Failed to fetch history";
|
|
9269
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9270
|
+
}
|
|
9271
|
+
} else if (req.method === "POST") {
|
|
9272
|
+
try {
|
|
9273
|
+
const body = await req.json().catch(() => ({}));
|
|
9274
|
+
const sid = body.sessionId || sessionId;
|
|
9275
|
+
await storage.clearHistory(sid);
|
|
9276
|
+
return NextResponse.json({ success: true });
|
|
9277
|
+
} catch (err) {
|
|
9278
|
+
const message = err instanceof Error ? err.message : "Failed to clear history";
|
|
9279
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9280
|
+
}
|
|
9281
|
+
}
|
|
9282
|
+
return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9283
|
+
};
|
|
9284
|
+
}
|
|
9285
|
+
function createFeedbackHandler(configOrPlugin, options) {
|
|
9286
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9287
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9288
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9289
|
+
return async function handler(req) {
|
|
9290
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9291
|
+
if (authResult) return authResult;
|
|
9292
|
+
if (req.method === "GET") {
|
|
9293
|
+
try {
|
|
9294
|
+
const url = new URL(req.url);
|
|
9295
|
+
const messageId = url.searchParams.get("messageId");
|
|
9296
|
+
if (!messageId) {
|
|
9297
|
+
const feedbackList = await storage.listFeedback();
|
|
9298
|
+
return NextResponse.json({ feedback: feedbackList });
|
|
9299
|
+
}
|
|
9300
|
+
const feedback = await storage.getFeedback(messageId);
|
|
9301
|
+
return NextResponse.json({ feedback });
|
|
9302
|
+
} catch (err) {
|
|
9303
|
+
const message = err instanceof Error ? err.message : "Failed to fetch feedback";
|
|
9304
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9305
|
+
}
|
|
9306
|
+
} else if (req.method === "POST") {
|
|
9307
|
+
try {
|
|
9308
|
+
const body = await req.json();
|
|
9309
|
+
const { messageId, sessionId = "default", rating, comment } = body;
|
|
9310
|
+
if (!messageId) {
|
|
9311
|
+
return NextResponse.json({ error: "messageId is required" }, { status: 400 });
|
|
9312
|
+
}
|
|
9313
|
+
if (!rating) {
|
|
9314
|
+
return NextResponse.json({ error: "rating is required" }, { status: 400 });
|
|
9315
|
+
}
|
|
9316
|
+
await storage.saveFeedback({ messageId, sessionId, rating, comment });
|
|
9317
|
+
return NextResponse.json({ success: true });
|
|
9318
|
+
} catch (err) {
|
|
9319
|
+
const message = err instanceof Error ? err.message : "Failed to save feedback";
|
|
9320
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9321
|
+
}
|
|
9322
|
+
}
|
|
9323
|
+
return NextResponse.json({ error: "Method Not Allowed" }, { status: 405 });
|
|
9324
|
+
};
|
|
9325
|
+
}
|
|
9326
|
+
function createSessionsHandler(configOrPlugin, options) {
|
|
9327
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9328
|
+
const storage = new DatabaseStorage(plugin.getConfig());
|
|
9329
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9330
|
+
return async function GET(req) {
|
|
9331
|
+
if (req) {
|
|
9332
|
+
const authResult = await checkAuth(req, onAuthorize);
|
|
9333
|
+
if (authResult) return authResult;
|
|
9334
|
+
}
|
|
9335
|
+
void req;
|
|
9336
|
+
try {
|
|
9337
|
+
const sessions = await storage.listSessions();
|
|
9338
|
+
return NextResponse.json({ sessions });
|
|
9339
|
+
} catch (err) {
|
|
9340
|
+
const message = err instanceof Error ? err.message : "Failed to list sessions";
|
|
9341
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
9342
|
+
}
|
|
9343
|
+
};
|
|
9344
|
+
}
|
|
9345
|
+
function createRagHandler(configOrPlugin, options) {
|
|
9346
|
+
const plugin = getOrCreatePlugin(configOrPlugin);
|
|
9347
|
+
const onAuthorize = options == null ? void 0 : options.onAuthorize;
|
|
9348
|
+
const chatHandler = createChatHandler(plugin, { onAuthorize });
|
|
9349
|
+
const streamHandler = createStreamHandler(plugin, { onAuthorize });
|
|
9350
|
+
const uploadHandler = createUploadHandler(plugin, { onAuthorize });
|
|
9351
|
+
const healthHandler = createHealthHandler(plugin, { onAuthorize });
|
|
9352
|
+
const suggestionsHandler = createSuggestionsHandler(plugin, { onAuthorize });
|
|
9353
|
+
const historyHandler = createHistoryHandler(plugin, { onAuthorize });
|
|
9354
|
+
const feedbackHandler = createFeedbackHandler(plugin, { onAuthorize });
|
|
9355
|
+
const sessionsHandler = createSessionsHandler(plugin, { onAuthorize });
|
|
7634
9356
|
async function routePostRequest(req, segment) {
|
|
7635
9357
|
switch (segment) {
|
|
7636
9358
|
case "chat":
|
|
@@ -7642,22 +9364,35 @@ function createRagHandler(configOrPlugin) {
|
|
|
7642
9364
|
case "suggestions":
|
|
7643
9365
|
return suggestionsHandler(req);
|
|
7644
9366
|
case "health":
|
|
7645
|
-
return healthHandler();
|
|
9367
|
+
return healthHandler(req);
|
|
9368
|
+
case "history":
|
|
9369
|
+
case "history/clear":
|
|
9370
|
+
return historyHandler(req);
|
|
9371
|
+
case "feedback":
|
|
9372
|
+
return feedbackHandler(req);
|
|
7646
9373
|
default:
|
|
7647
9374
|
return NextResponse.json({ error: `Not Found: POST segment "${segment}" not supported.` }, { status: 404 });
|
|
7648
9375
|
}
|
|
7649
9376
|
}
|
|
7650
9377
|
async function routeGetRequest(req, segment) {
|
|
7651
|
-
|
|
7652
|
-
|
|
9378
|
+
switch (segment) {
|
|
9379
|
+
case "health":
|
|
9380
|
+
return healthHandler(req);
|
|
9381
|
+
case "history":
|
|
9382
|
+
return historyHandler(req);
|
|
9383
|
+
case "feedback":
|
|
9384
|
+
return feedbackHandler(req);
|
|
9385
|
+
case "sessions":
|
|
9386
|
+
return sessionsHandler(req);
|
|
9387
|
+
default:
|
|
9388
|
+
return NextResponse.json({ error: `Method Not Allowed: GET segment "${segment}" not supported.` }, { status: 405 });
|
|
7653
9389
|
}
|
|
7654
|
-
return NextResponse.json({ error: `Method Not Allowed: GET is only supported for "health" segment.` }, { status: 405 });
|
|
7655
9390
|
}
|
|
7656
9391
|
async function getSegment(context) {
|
|
7657
|
-
var
|
|
7658
|
-
const resolvedParams = typeof ((
|
|
9392
|
+
var _a2;
|
|
9393
|
+
const resolvedParams = typeof ((_a2 = context == null ? void 0 : context.params) == null ? void 0 : _a2.then) === "function" ? await context.params : context == null ? void 0 : context.params;
|
|
7659
9394
|
const segments = (resolvedParams == null ? void 0 : resolvedParams.retrivora) || [];
|
|
7660
|
-
return segments
|
|
9395
|
+
return segments.join("/") || "chat";
|
|
7661
9396
|
}
|
|
7662
9397
|
return {
|
|
7663
9398
|
GET: async (req, context) => {
|
|
@@ -7682,9 +9417,12 @@ function createRagHandler(configOrPlugin) {
|
|
|
7682
9417
|
}
|
|
7683
9418
|
export {
|
|
7684
9419
|
createChatHandler,
|
|
9420
|
+
createFeedbackHandler,
|
|
7685
9421
|
createHealthHandler,
|
|
9422
|
+
createHistoryHandler,
|
|
7686
9423
|
createIngestHandler,
|
|
7687
9424
|
createRagHandler,
|
|
9425
|
+
createSessionsHandler,
|
|
7688
9426
|
createStreamHandler,
|
|
7689
9427
|
createSuggestionsHandler,
|
|
7690
9428
|
createUploadHandler,
|