@retrivora-ai/rag-engine 2.0.6 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/handlers/index.js +167 -50
- package/dist/handlers/index.mjs +167 -50
- package/dist/index.js +79 -22
- package/dist/index.mjs +79 -22
- package/dist/server.js +167 -50
- package/dist/server.mjs +167 -50
- package/package.json +1 -1
- package/src/core/Pipeline.ts +51 -13
- package/src/core/QueryProcessor.ts +3 -3
- package/src/llm/providers/UniversalLLMAdapter.ts +17 -15
- package/src/rag/Reranker.ts +2 -2
- package/src/rendering/IntentClassifier.ts +1 -1
- package/src/rendering/RendererRegistry.ts +1 -1
- package/src/utils/ProductExtractor.ts +1 -1
- package/src/utils/UITransformer.ts +62 -17
package/dist/server.mjs
CHANGED
|
@@ -3938,9 +3938,9 @@ ${context != null ? context : "None"}` },
|
|
|
3938
3938
|
}
|
|
3939
3939
|
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
3940
3940
|
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3941
|
+
const _g2 = globalThis;
|
|
3942
|
+
if (typeof _g2.__retrivoraDispatchChat === "function") {
|
|
3943
|
+
try {
|
|
3944
3944
|
const res = await _g2.__retrivoraDispatchChat({
|
|
3945
3945
|
model: this.model,
|
|
3946
3946
|
messages: formattedMessages,
|
|
@@ -3950,8 +3950,9 @@ ${context != null ? context : "None"}` },
|
|
|
3950
3950
|
if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
|
|
3951
3951
|
return res.response.choices[0].message.content;
|
|
3952
3952
|
}
|
|
3953
|
+
} catch (dispatchErr) {
|
|
3954
|
+
throw dispatchErr;
|
|
3953
3955
|
}
|
|
3954
|
-
} catch (e) {
|
|
3955
3956
|
}
|
|
3956
3957
|
}
|
|
3957
3958
|
const { data } = await this.http.post(path2, payload);
|
|
@@ -4003,9 +4004,9 @@ ${context != null ? context : "None"}` },
|
|
|
4003
4004
|
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4004
4005
|
let streamBody = null;
|
|
4005
4006
|
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4007
|
+
const _g3 = globalThis;
|
|
4008
|
+
if (typeof _g3.__retrivoraDispatchChat === "function") {
|
|
4009
|
+
try {
|
|
4009
4010
|
const res = yield new __await(_g3.__retrivoraDispatchChat({
|
|
4010
4011
|
model: this.model,
|
|
4011
4012
|
messages: formattedMessages,
|
|
@@ -4019,8 +4020,9 @@ ${context != null ? context : "None"}` },
|
|
|
4019
4020
|
yield res.response.choices[0].message.content;
|
|
4020
4021
|
return;
|
|
4021
4022
|
}
|
|
4023
|
+
} catch (dispatchErr) {
|
|
4024
|
+
throw dispatchErr;
|
|
4022
4025
|
}
|
|
4023
|
-
} catch (e) {
|
|
4024
4026
|
}
|
|
4025
4027
|
}
|
|
4026
4028
|
if (!streamBody) {
|
|
@@ -4091,9 +4093,9 @@ ${context != null ? context : "None"}` },
|
|
|
4091
4093
|
}
|
|
4092
4094
|
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4093
4095
|
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4096
|
+
const _g2 = globalThis;
|
|
4097
|
+
if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
|
|
4098
|
+
try {
|
|
4097
4099
|
const res = await _g2.__retrivoraDispatchEmbedding({
|
|
4098
4100
|
model: this.model,
|
|
4099
4101
|
input: text
|
|
@@ -4101,8 +4103,9 @@ ${context != null ? context : "None"}` },
|
|
|
4101
4103
|
if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
|
|
4102
4104
|
return res.data[0].embedding;
|
|
4103
4105
|
}
|
|
4106
|
+
} catch (dispatchErr) {
|
|
4107
|
+
throw dispatchErr;
|
|
4104
4108
|
}
|
|
4105
|
-
} catch (e) {
|
|
4106
4109
|
}
|
|
4107
4110
|
}
|
|
4108
4111
|
const { data } = await this.http.post(path2, payload);
|
|
@@ -4695,7 +4698,8 @@ var Reranker = class {
|
|
|
4695
4698
|
return matches.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
4696
4699
|
}
|
|
4697
4700
|
const scoredMatches = matches.map((match) => {
|
|
4698
|
-
|
|
4701
|
+
var _a2;
|
|
4702
|
+
const contentLower = ((_a2 = match == null ? void 0 : match.content) != null ? _a2 : "").toLowerCase();
|
|
4699
4703
|
let keywordScore = 0;
|
|
4700
4704
|
keywords.forEach((keyword) => {
|
|
4701
4705
|
if (contentLower.includes(keyword)) {
|
|
@@ -4716,7 +4720,10 @@ var Reranker = class {
|
|
|
4716
4720
|
[{ role: "user", content: `Query: "${query}"
|
|
4717
4721
|
|
|
4718
4722
|
Documents:
|
|
4719
|
-
${topN.map((m, i) =>
|
|
4723
|
+
${topN.map((m, i) => {
|
|
4724
|
+
var _a2;
|
|
4725
|
+
return `[${i}] ${((_a2 = m == null ? void 0 : m.content) != null ? _a2 : "").replace(/\n/g, " ")}`;
|
|
4726
|
+
}).join("\n")}` }],
|
|
4720
4727
|
"",
|
|
4721
4728
|
{
|
|
4722
4729
|
systemPrompt: 'You are a relevance ranking expert. Given the user query and a list of retrieved document chunks, rank the chunks by relevance to the query. Return the result as a comma-separated list of document indices in order of relevance, from most relevant to least relevant. Use the indices provided in brackets like [0], [1], etc. Only return the indices (e.g., "2,0,1"), nothing else. Do not include brackets in the output.',
|
|
@@ -5887,10 +5894,10 @@ Return ONLY 'vector', 'graph', or 'both'. No explanation.`;
|
|
|
5887
5894
|
"",
|
|
5888
5895
|
{ temperature: 0, maxTokens: 10 }
|
|
5889
5896
|
);
|
|
5890
|
-
const cleanResponse = response.trim().toLowerCase();
|
|
5891
|
-
if (cleanResponse.includes("vector")) return "vector";
|
|
5892
|
-
if (cleanResponse.includes("graph")) return "graph";
|
|
5897
|
+
const cleanResponse = (response != null ? response : "").trim().toLowerCase();
|
|
5893
5898
|
if (cleanResponse.includes("both")) return "both";
|
|
5899
|
+
if (cleanResponse.includes("graph")) return "graph";
|
|
5900
|
+
if (cleanResponse.includes("vector")) return "vector";
|
|
5894
5901
|
} catch (error) {
|
|
5895
5902
|
console.warn("[QueryProcessor] LLM strategy classification failed, falling back to keywords:", error);
|
|
5896
5903
|
}
|
|
@@ -6064,7 +6071,10 @@ var IntentClassifier = class {
|
|
|
6064
6071
|
hasCategoricalFields = catKeys.size > 0;
|
|
6065
6072
|
numericFieldCount = numericKeys.size;
|
|
6066
6073
|
categoricalFieldCount = catKeys.size;
|
|
6067
|
-
if (productKeyMatches >= 2 || docs.some((d) =>
|
|
6074
|
+
if (productKeyMatches >= 2 || docs.some((d) => {
|
|
6075
|
+
var _a2, _b;
|
|
6076
|
+
return ((_a2 = d == null ? void 0 : d.content) != null ? _a2 : "").toLowerCase().includes("price") || ((_b = d == null ? void 0 : d.content) != null ? _b : "").toLowerCase().includes("brand");
|
|
6077
|
+
})) {
|
|
6068
6078
|
isProductLike = true;
|
|
6069
6079
|
}
|
|
6070
6080
|
}
|
|
@@ -6344,7 +6354,10 @@ var TextRendererStrategy = class {
|
|
|
6344
6354
|
return { type: "text", title, data: { content: data } };
|
|
6345
6355
|
}
|
|
6346
6356
|
const docs = Array.isArray(data) ? data : [];
|
|
6347
|
-
const text = docs.map((d) =>
|
|
6357
|
+
const text = docs.map((d) => {
|
|
6358
|
+
var _a2;
|
|
6359
|
+
return (_a2 = d == null ? void 0 : d.content) != null ? _a2 : "";
|
|
6360
|
+
}).join("\n\n");
|
|
6348
6361
|
return { type: "text", title, data: { content: text || "No detailed content available." } };
|
|
6349
6362
|
}
|
|
6350
6363
|
};
|
|
@@ -6601,6 +6614,19 @@ var UITransformer = class _UITransformer {
|
|
|
6601
6614
|
if (!retrievedData || retrievedData.length === 0) {
|
|
6602
6615
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
6603
6616
|
}
|
|
6617
|
+
console.log("[UITransformer.transform] Processing retrievedData:", {
|
|
6618
|
+
userQuery,
|
|
6619
|
+
retrievedCount: retrievedData.length,
|
|
6620
|
+
sample: retrievedData.slice(0, 2).map((item) => {
|
|
6621
|
+
var _a3;
|
|
6622
|
+
return {
|
|
6623
|
+
id: item == null ? void 0 : item.id,
|
|
6624
|
+
contentType: typeof (item == null ? void 0 : item.content),
|
|
6625
|
+
contentSnippet: String((_a3 = item == null ? void 0 : item.content) != null ? _a3 : "").substring(0, 150),
|
|
6626
|
+
metadataKeys: Object.keys((item == null ? void 0 : item.metadata) || {})
|
|
6627
|
+
};
|
|
6628
|
+
})
|
|
6629
|
+
});
|
|
6604
6630
|
const resolvedIntent = intent != null ? intent : this.detectIntentHeuristic(userQuery);
|
|
6605
6631
|
const filteredData = resolvedIntent.filterInStockOnly ? retrievedData.filter((item) => this.determineStockStatus(item)) : retrievedData;
|
|
6606
6632
|
const profile = this.profileData(filteredData);
|
|
@@ -7090,7 +7116,10 @@ ${schemaProfileText}` : ""}`;
|
|
|
7090
7116
|
type: "radar_chart",
|
|
7091
7117
|
title: "Product Comparison",
|
|
7092
7118
|
description: `Comparing ${data.length} items across ${radarData.length} attributes`,
|
|
7093
|
-
data: radarData.length > 0 ? radarData : data.map((d) =>
|
|
7119
|
+
data: radarData.length > 0 ? radarData : data.map((d) => {
|
|
7120
|
+
var _a2;
|
|
7121
|
+
return { attribute: ((_a2 = d == null ? void 0 : d.content) != null ? _a2 : "").substring(0, 40) };
|
|
7122
|
+
})
|
|
7094
7123
|
};
|
|
7095
7124
|
}
|
|
7096
7125
|
static transformToTable(data, query = "") {
|
|
@@ -7107,7 +7136,10 @@ ${schemaProfileText}` : ""}`;
|
|
|
7107
7136
|
static transformToText(data) {
|
|
7108
7137
|
return this.createTextResponse(
|
|
7109
7138
|
"Retrieved Context",
|
|
7110
|
-
data.map((item) =>
|
|
7139
|
+
data.map((item) => {
|
|
7140
|
+
var _a2;
|
|
7141
|
+
return (_a2 = item == null ? void 0 : item.content) != null ? _a2 : "";
|
|
7142
|
+
}).join("\n\n"),
|
|
7111
7143
|
`Found ${data.length} relevant results`
|
|
7112
7144
|
);
|
|
7113
7145
|
}
|
|
@@ -7268,6 +7300,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
7268
7300
|
return productTerms && productAction && !nonProductEntityTerms;
|
|
7269
7301
|
}
|
|
7270
7302
|
static isProductData(item) {
|
|
7303
|
+
if (!item) return false;
|
|
7271
7304
|
const content = (item.content || "").toLowerCase();
|
|
7272
7305
|
const productKeywords = [
|
|
7273
7306
|
"product",
|
|
@@ -7526,12 +7559,12 @@ ${schemaProfileText}` : ""}`;
|
|
|
7526
7559
|
}
|
|
7527
7560
|
static extractTimeSeriesData(data) {
|
|
7528
7561
|
return data.map((item) => {
|
|
7529
|
-
var _a2, _b, _c, _d, _e;
|
|
7562
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
7530
7563
|
const meta = item.metadata || {};
|
|
7531
7564
|
return {
|
|
7532
7565
|
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
7533
7566
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
7534
|
-
label: (
|
|
7567
|
+
label: (_f = meta.label) != null ? _f : ((_e = item == null ? void 0 : item.content) != null ? _e : "").substring(0, 50)
|
|
7535
7568
|
};
|
|
7536
7569
|
});
|
|
7537
7570
|
}
|
|
@@ -7645,7 +7678,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
7645
7678
|
}, query.includes(normalizedField) ? 3 : 0);
|
|
7646
7679
|
}
|
|
7647
7680
|
static resolveTableCellValue(item, column) {
|
|
7648
|
-
|
|
7681
|
+
var _a2, _b, _c;
|
|
7682
|
+
if (column === "Content") return ((_a2 = item == null ? void 0 : item.content) != null ? _a2 : "").substring(0, 100);
|
|
7649
7683
|
const meta = item.metadata || {};
|
|
7650
7684
|
const normalizedColumn = this.normalizeComparableField(column);
|
|
7651
7685
|
const exactMetadata = Object.entries(meta).find(
|
|
@@ -7656,9 +7690,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
7656
7690
|
}
|
|
7657
7691
|
const aliasValue = this.resolveAliasedTableCell(meta, column);
|
|
7658
7692
|
if (aliasValue !== void 0) return this.toDisplayValue(aliasValue);
|
|
7659
|
-
const contentValue = this.extractContentFieldValue(item.content, column);
|
|
7693
|
+
const contentValue = this.extractContentFieldValue((_b = item == null ? void 0 : item.content) != null ? _b : "", column);
|
|
7660
7694
|
if (contentValue !== null) return contentValue;
|
|
7661
|
-
const aliasContentValue = this.extractAliasedContentFieldValue(item.content, column);
|
|
7695
|
+
const aliasContentValue = this.extractAliasedContentFieldValue((_c = item == null ? void 0 : item.content) != null ? _c : "", column);
|
|
7662
7696
|
return aliasContentValue != null ? aliasContentValue : "";
|
|
7663
7697
|
}
|
|
7664
7698
|
static resolveAliasedTableCell(meta, column) {
|
|
@@ -7708,6 +7742,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
7708
7742
|
return { inStockCount: inStock, outOfStockCount: outOfStock };
|
|
7709
7743
|
}
|
|
7710
7744
|
static determineStockStatus(item) {
|
|
7745
|
+
if (!item) return true;
|
|
7711
7746
|
const meta = item.metadata || {};
|
|
7712
7747
|
const stockValue = resolveMetadataValue(meta, "stock");
|
|
7713
7748
|
if (stockValue !== void 0) {
|
|
@@ -7753,35 +7788,64 @@ ${schemaProfileText}` : ""}`;
|
|
|
7753
7788
|
return resolveMetadataValue(meta, uiKey);
|
|
7754
7789
|
}
|
|
7755
7790
|
static extractProductInfo(item, config, trainedSchema) {
|
|
7756
|
-
var _a2;
|
|
7791
|
+
var _a2, _b;
|
|
7792
|
+
if (!item) return null;
|
|
7757
7793
|
const meta = item.metadata || {};
|
|
7794
|
+
const content = item.content || "";
|
|
7758
7795
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
7759
7796
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
7760
7797
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
7761
7798
|
const description = this.cleanProductDescription(
|
|
7762
|
-
(_a2 = this.extractProductDescriptionFromContent(
|
|
7799
|
+
(_a2 = this.extractProductDescriptionFromContent(content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
7763
7800
|
);
|
|
7764
7801
|
if (name || this.isProductData(item)) {
|
|
7765
7802
|
let finalName = name ? String(name) : void 0;
|
|
7803
|
+
if (!finalName && content) {
|
|
7804
|
+
const nameMatch = content.match(/(?:Product|Item|Name):\s*([^\n]+)/i);
|
|
7805
|
+
finalName = nameMatch ? nameMatch[1].trim() : (_b = content.split("\n")[0]) == null ? void 0 : _b.substring(0, 60);
|
|
7806
|
+
}
|
|
7766
7807
|
if (!finalName) {
|
|
7767
|
-
|
|
7768
|
-
|
|
7808
|
+
console.warn(
|
|
7809
|
+
`[UITransformer] Unable to read product name from metadata or content for item ${item.id}. Defaulting to 'Unnamed Product'.`,
|
|
7810
|
+
{ metadataKeys: Object.keys(meta), contentLength: content.length }
|
|
7811
|
+
);
|
|
7769
7812
|
}
|
|
7770
7813
|
let finalPrice = typeof price === "number" || typeof price === "string" ? price : void 0;
|
|
7771
|
-
if (!finalPrice) {
|
|
7772
|
-
const priceMatch =
|
|
7814
|
+
if (!finalPrice && content) {
|
|
7815
|
+
const priceMatch = content.match(/(?:Price|Cost):\s*\$?([\d,.]+)/i) || content.match(/\$\s*([\d,.]+)/);
|
|
7773
7816
|
if (priceMatch) finalPrice = priceMatch[1].replace(/,/g, "");
|
|
7774
7817
|
}
|
|
7818
|
+
if (finalPrice === void 0) {
|
|
7819
|
+
console.warn(
|
|
7820
|
+
`[UITransformer] Unable to read product price from metadata or content for item ${item.id}.`,
|
|
7821
|
+
{ metadataKeys: Object.keys(meta), contentSnippet: content.substring(0, 100) }
|
|
7822
|
+
);
|
|
7823
|
+
}
|
|
7775
7824
|
const imageValue = this.getDynamicVal(meta, "image", config, trainedSchema);
|
|
7825
|
+
if (!imageValue) {
|
|
7826
|
+
console.debug(
|
|
7827
|
+
`[UITransformer] Unable to read product image URL from metadata for item ${item.id}.`
|
|
7828
|
+
);
|
|
7829
|
+
}
|
|
7830
|
+
if (!description) {
|
|
7831
|
+
console.debug(
|
|
7832
|
+
`[UITransformer] Unable to read product description from metadata or content for item ${item.id}.`
|
|
7833
|
+
);
|
|
7834
|
+
}
|
|
7776
7835
|
return {
|
|
7777
7836
|
id: item.id,
|
|
7778
|
-
name: finalName,
|
|
7837
|
+
name: finalName || "Unnamed Product",
|
|
7779
7838
|
price: finalPrice,
|
|
7780
7839
|
image: typeof imageValue === "string" ? imageValue : void 0,
|
|
7781
7840
|
brand: brand ? String(brand) : void 0,
|
|
7782
7841
|
description,
|
|
7783
7842
|
inStock: this.determineStockStatus(item)
|
|
7784
7843
|
};
|
|
7844
|
+
} else {
|
|
7845
|
+
console.warn(
|
|
7846
|
+
`[UITransformer] Item ${item.id} skipped: unable to read name or identify as product data from metadata/content.`,
|
|
7847
|
+
{ metadataKeys: Object.keys(meta), contentSnippet: content.substring(0, 100) }
|
|
7848
|
+
);
|
|
7785
7849
|
}
|
|
7786
7850
|
return null;
|
|
7787
7851
|
}
|
|
@@ -7866,13 +7930,13 @@ RULES:
|
|
|
7866
7930
|
5. If no relevant data is found, return text: "I cannot answer this question based on the available information."`;
|
|
7867
7931
|
}
|
|
7868
7932
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
7869
|
-
const items = sources.map((s, i) => {
|
|
7933
|
+
const items = (sources || []).filter(Boolean).map((s, i) => {
|
|
7870
7934
|
var _a2, _b, _c, _d;
|
|
7871
7935
|
return {
|
|
7872
7936
|
index: i + 1,
|
|
7873
|
-
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
7874
|
-
metadata: (_c = s.metadata) != null ? _c : {},
|
|
7875
|
-
score: (_d = s.score) != null ? _d : 0
|
|
7937
|
+
content: (_b = (_a2 = s == null ? void 0 : s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
7938
|
+
metadata: (_c = s == null ? void 0 : s.metadata) != null ? _c : {},
|
|
7939
|
+
score: (_d = s == null ? void 0 : s.score) != null ? _d : 0
|
|
7876
7940
|
};
|
|
7877
7941
|
});
|
|
7878
7942
|
const full = JSON.stringify(items, null, 2);
|
|
@@ -8441,17 +8505,33 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
8441
8505
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
8442
8506
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
8443
8507
|
const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
|
|
8444
|
-
const rawSources = (strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : [];
|
|
8508
|
+
const rawSources = ((strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : []).filter((s) => Boolean(s && typeof s === "object"));
|
|
8509
|
+
console.log("[Pipeline] Raw vectorDB.query response:", {
|
|
8510
|
+
rawCount: rawSources.length,
|
|
8511
|
+
sample: rawSources.slice(0, 2).map((s) => {
|
|
8512
|
+
var _a3;
|
|
8513
|
+
return {
|
|
8514
|
+
id: s == null ? void 0 : s.id,
|
|
8515
|
+
score: s == null ? void 0 : s.score,
|
|
8516
|
+
contentType: typeof (s == null ? void 0 : s.content),
|
|
8517
|
+
contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
|
|
8518
|
+
metadataKeys: Object.keys((s == null ? void 0 : s.metadata) || {})
|
|
8519
|
+
};
|
|
8520
|
+
})
|
|
8521
|
+
});
|
|
8445
8522
|
const retrieveEnd = performance.now();
|
|
8446
8523
|
const embedMs = retrieveEnd - embedStart;
|
|
8447
8524
|
const retrieveMs = retrieveEnd - embedStart;
|
|
8448
8525
|
const rerankStart = performance.now();
|
|
8449
|
-
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
8450
|
-
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) =>
|
|
8526
|
+
const structuredSources = this.applyStructuredFilters(rawSources, filter).filter((s) => Boolean(s && typeof s === "object"));
|
|
8527
|
+
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => {
|
|
8528
|
+
var _a3;
|
|
8529
|
+
return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= scoreThreshold;
|
|
8530
|
+
});
|
|
8451
8531
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
8452
8532
|
const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
|
|
8453
8533
|
if (!hasNumericPredicates && useReranking) {
|
|
8454
|
-
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
8534
|
+
fullSources = (yield new __await(this.reranker.rerank(fullSources, question, rerankLimit))).filter((s) => Boolean(s && typeof s === "object"));
|
|
8455
8535
|
} else if (!wantsExhaustiveList) {
|
|
8456
8536
|
fullSources = fullSources.slice(0, topK);
|
|
8457
8537
|
}
|
|
@@ -8466,13 +8546,33 @@ ${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
|
|
|
8466
8546
|
displayCount = fullSources.length;
|
|
8467
8547
|
} else {
|
|
8468
8548
|
const baseThreshold = Math.max(scoreThreshold, 0.4);
|
|
8469
|
-
const highlyRelevant = fullSources.filter((m) =>
|
|
8549
|
+
const highlyRelevant = fullSources.filter((m) => {
|
|
8550
|
+
var _a3;
|
|
8551
|
+
return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= baseThreshold;
|
|
8552
|
+
});
|
|
8470
8553
|
displayCount = Math.max(highlyRelevant.length, topK);
|
|
8471
8554
|
if (displayCount > 15) {
|
|
8472
8555
|
displayCount = 15;
|
|
8473
8556
|
}
|
|
8474
8557
|
}
|
|
8475
|
-
const sources = [...fullSources].
|
|
8558
|
+
const sources = [...fullSources].filter((s) => Boolean(s && typeof s === "object")).sort((a, b) => {
|
|
8559
|
+
var _a3, _b2;
|
|
8560
|
+
return ((_a3 = b == null ? void 0 : b.score) != null ? _a3 : 0) - ((_b2 = a == null ? void 0 : a.score) != null ? _b2 : 0);
|
|
8561
|
+
}).slice(0, displayCount);
|
|
8562
|
+
console.log("[Pipeline] Final sources for prompt & UI:", {
|
|
8563
|
+
count: sources.length,
|
|
8564
|
+
sources: sources.map((s, idx) => {
|
|
8565
|
+
var _a3;
|
|
8566
|
+
return {
|
|
8567
|
+
rank: idx + 1,
|
|
8568
|
+
id: s == null ? void 0 : s.id,
|
|
8569
|
+
score: s == null ? void 0 : s.score,
|
|
8570
|
+
contentType: typeof (s == null ? void 0 : s.content),
|
|
8571
|
+
contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
|
|
8572
|
+
metadata: s == null ? void 0 : s.metadata
|
|
8573
|
+
};
|
|
8574
|
+
})
|
|
8575
|
+
});
|
|
8476
8576
|
if (graphData && graphData.nodes.length > 0) {
|
|
8477
8577
|
const graphContext = graphData.nodes.map(
|
|
8478
8578
|
(n) => `Entity: ${n.label} (${n.id})${n.properties ? " - " + JSON.stringify(n.properties) : ""}`
|
|
@@ -8498,18 +8598,18 @@ ${context}`;
|
|
|
8498
8598
|
}
|
|
8499
8599
|
yield {
|
|
8500
8600
|
reply: "",
|
|
8501
|
-
sources: sources.map((s) => {
|
|
8502
|
-
var _a3;
|
|
8601
|
+
sources: (sources || []).filter((s) => Boolean(s && typeof s === "object")).map((s) => {
|
|
8602
|
+
var _a3, _b2, _c2;
|
|
8503
8603
|
return {
|
|
8504
8604
|
id: s.id,
|
|
8505
|
-
score: s.score,
|
|
8506
|
-
content: s.content,
|
|
8507
|
-
metadata: (
|
|
8605
|
+
score: (_a3 = s.score) != null ? _a3 : 0,
|
|
8606
|
+
content: (_b2 = s == null ? void 0 : s.content) != null ? _b2 : "",
|
|
8607
|
+
metadata: (_c2 = s == null ? void 0 : s.metadata) != null ? _c2 : {},
|
|
8508
8608
|
namespace: ns
|
|
8509
8609
|
};
|
|
8510
8610
|
})
|
|
8511
8611
|
};
|
|
8512
|
-
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
8612
|
+
const allMetadataKeys = Array.from(new Set(sources.filter(Boolean).flatMap((s) => Object.keys((s == null ? void 0 : s.metadata) || {}))));
|
|
8513
8613
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
8514
8614
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
8515
8615
|
SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => {
|
|
@@ -8801,6 +8901,8 @@ ${context}`;
|
|
|
8801
8901
|
});
|
|
8802
8902
|
}
|
|
8803
8903
|
resolveNumericPredicateValue(source, predicate) {
|
|
8904
|
+
var _a2;
|
|
8905
|
+
if (!source) return null;
|
|
8804
8906
|
const meta = source.metadata || {};
|
|
8805
8907
|
const field = predicate.field;
|
|
8806
8908
|
const entries = Object.entries(meta).filter(([, value]) => value !== null && value !== void 0 && typeof value !== "object");
|
|
@@ -8812,7 +8914,7 @@ ${context}`;
|
|
|
8812
8914
|
const value = this.toFiniteNumber(Array.isArray(fuzzy) ? fuzzy[1] : fuzzy.value);
|
|
8813
8915
|
if (value !== null) return value;
|
|
8814
8916
|
}
|
|
8815
|
-
const contentValue = this.extractNumericValueFromContent(source.content, field);
|
|
8917
|
+
const contentValue = this.extractNumericValueFromContent((_a2 = source.content) != null ? _a2 : "", field);
|
|
8816
8918
|
if (contentValue !== null) return contentValue;
|
|
8817
8919
|
}
|
|
8818
8920
|
for (const [key, value] of entries) {
|
|
@@ -8823,6 +8925,7 @@ ${context}`;
|
|
|
8823
8925
|
return null;
|
|
8824
8926
|
}
|
|
8825
8927
|
extractNumericValueFromContent(content, field) {
|
|
8928
|
+
if (!content || typeof content !== "string") return null;
|
|
8826
8929
|
const escapedWords = field.split(/\s+|_+|-+/).filter(Boolean).map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
8827
8930
|
if (escapedWords.length === 0) return null;
|
|
8828
8931
|
const pattern = new RegExp(`(?:${escapedWords.join("[\\\\s_:-]*")})\\s*[:\\-\u2013]?\\s*([\\d,]+(?:\\.\\d+)?)`, "i");
|
|
@@ -8908,6 +9011,20 @@ ${context}`;
|
|
|
8908
9011
|
resolvedSources.push(source);
|
|
8909
9012
|
}
|
|
8910
9013
|
}
|
|
9014
|
+
console.log("[Pipeline] retrieve() response:", {
|
|
9015
|
+
query,
|
|
9016
|
+
namespace: ns,
|
|
9017
|
+
count: resolvedSources.length,
|
|
9018
|
+
sample: resolvedSources.slice(0, 2).map((s) => {
|
|
9019
|
+
var _a3;
|
|
9020
|
+
return {
|
|
9021
|
+
id: s == null ? void 0 : s.id,
|
|
9022
|
+
score: s == null ? void 0 : s.score,
|
|
9023
|
+
contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
|
|
9024
|
+
metadata: s == null ? void 0 : s.metadata
|
|
9025
|
+
};
|
|
9026
|
+
})
|
|
9027
|
+
});
|
|
8911
9028
|
return { sources: resolvedSources, graphData };
|
|
8912
9029
|
}
|
|
8913
9030
|
/** Rewrite the user query for better retrieval performance. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.7",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "UNLICENSED",
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -583,9 +583,20 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
583
583
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
584
584
|
const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
|
|
585
585
|
|
|
586
|
-
const rawSources = (strategyResult === 'vector' || strategyResult === 'both') && queryVector && queryVector.length > 0
|
|
586
|
+
const rawSources = ((strategyResult === 'vector' || strategyResult === 'both') && queryVector && queryVector.length > 0
|
|
587
587
|
? await this.vectorDB.query(queryVector, retrievalLimit, ns, filter)
|
|
588
|
-
: [];
|
|
588
|
+
: []).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'));
|
|
589
|
+
|
|
590
|
+
console.log('[Pipeline] Raw vectorDB.query response:', {
|
|
591
|
+
rawCount: rawSources.length,
|
|
592
|
+
sample: rawSources.slice(0, 2).map((s) => ({
|
|
593
|
+
id: s?.id,
|
|
594
|
+
score: s?.score,
|
|
595
|
+
contentType: typeof s?.content,
|
|
596
|
+
contentSnippet: String(s?.content ?? '').substring(0, 150),
|
|
597
|
+
metadataKeys: Object.keys(s?.metadata || {}),
|
|
598
|
+
})),
|
|
599
|
+
});
|
|
589
600
|
|
|
590
601
|
const retrieveEnd = performance.now();
|
|
591
602
|
const embedMs = retrieveEnd - embedStart;
|
|
@@ -593,14 +604,14 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
593
604
|
|
|
594
605
|
// 3. Reranking
|
|
595
606
|
const rerankStart = performance.now();
|
|
596
|
-
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
607
|
+
const structuredSources = this.applyStructuredFilters(rawSources, filter).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'));
|
|
597
608
|
let fullSources = hasNumericPredicates
|
|
598
609
|
? structuredSources
|
|
599
|
-
: structuredSources.filter((m) => m
|
|
610
|
+
: structuredSources.filter((m) => (m?.score ?? 0) >= scoreThreshold);
|
|
600
611
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
601
612
|
const useReranking = arch !== 'naive' && (arch === 'retrieve-and-rerank' || this.config.rag?.useReranking);
|
|
602
613
|
if (!hasNumericPredicates && useReranking) {
|
|
603
|
-
fullSources = await this.reranker.rerank(fullSources, question, rerankLimit);
|
|
614
|
+
fullSources = (await this.reranker.rerank(fullSources, question, rerankLimit)).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'));
|
|
604
615
|
} else if (!wantsExhaustiveList) {
|
|
605
616
|
fullSources = fullSources.slice(0, topK);
|
|
606
617
|
}
|
|
@@ -620,7 +631,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
620
631
|
} else {
|
|
621
632
|
// For general semantic queries, count the number of matches meeting high relevance threshold
|
|
622
633
|
const baseThreshold = Math.max(scoreThreshold, 0.4);
|
|
623
|
-
const highlyRelevant = fullSources.filter(m => m
|
|
634
|
+
const highlyRelevant = fullSources.filter(m => (m?.score ?? 0) >= baseThreshold);
|
|
624
635
|
displayCount = Math.max(highlyRelevant.length, topK);
|
|
625
636
|
// Cap non-metadata semantic searches to a maximum of 15 to keep the UI clean
|
|
626
637
|
if (displayCount > 15) {
|
|
@@ -630,9 +641,22 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
630
641
|
|
|
631
642
|
// Ensure they are sorted from highest to lowest score, then slice using our dynamic count
|
|
632
643
|
const sources = [...fullSources]
|
|
633
|
-
.
|
|
644
|
+
.filter((s): s is VectorMatch => Boolean(s && typeof s === 'object'))
|
|
645
|
+
.sort((a, b) => (b?.score ?? 0) - (a?.score ?? 0))
|
|
634
646
|
.slice(0, displayCount);
|
|
635
647
|
|
|
648
|
+
console.log('[Pipeline] Final sources for prompt & UI:', {
|
|
649
|
+
count: sources.length,
|
|
650
|
+
sources: sources.map((s, idx) => ({
|
|
651
|
+
rank: idx + 1,
|
|
652
|
+
id: s?.id,
|
|
653
|
+
score: s?.score,
|
|
654
|
+
contentType: typeof s?.content,
|
|
655
|
+
contentSnippet: String(s?.content ?? '').substring(0, 150),
|
|
656
|
+
metadata: s?.metadata,
|
|
657
|
+
})),
|
|
658
|
+
});
|
|
659
|
+
|
|
636
660
|
if (graphData && graphData.nodes.length > 0) {
|
|
637
661
|
const graphContext = graphData.nodes.map(n =>
|
|
638
662
|
`Entity: ${n.label} (${n.id})${n.properties ? ' - ' + JSON.stringify(n.properties) : ''}`
|
|
@@ -653,17 +677,17 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
653
677
|
// Yield sources immediately to support early UI citation rendering (highly responsive)
|
|
654
678
|
yield {
|
|
655
679
|
reply: '',
|
|
656
|
-
sources: sources.map((s) => ({
|
|
680
|
+
sources: (sources || []).filter((s): s is VectorMatch => Boolean(s && typeof s === 'object')).map((s) => ({
|
|
657
681
|
id: s.id,
|
|
658
|
-
score: s.score,
|
|
659
|
-
content: s
|
|
660
|
-
metadata: s
|
|
682
|
+
score: s.score ?? 0,
|
|
683
|
+
content: s?.content ?? '',
|
|
684
|
+
metadata: s?.metadata ?? {},
|
|
661
685
|
namespace: ns,
|
|
662
686
|
} satisfies RetrievedChunk)),
|
|
663
687
|
} as ChatResponse;
|
|
664
688
|
|
|
665
689
|
// 4.5 Schema Training — true fire-and-forget, never gates anything.
|
|
666
|
-
const allMetadataKeys = Array.from(new Set(sources.flatMap(s => Object.keys(s
|
|
690
|
+
const allMetadataKeys = Array.from(new Set(sources.filter(Boolean).flatMap(s => Object.keys(s?.metadata || {}))));
|
|
667
691
|
const cachedSchema = allMetadataKeys.length > 0
|
|
668
692
|
? SchemaMapper.getCached(ns, allMetadataKeys)
|
|
669
693
|
: undefined;
|
|
@@ -1015,6 +1039,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
1015
1039
|
}
|
|
1016
1040
|
|
|
1017
1041
|
private resolveNumericPredicateValue(source: VectorMatch, predicate: NumericPredicate): number | null {
|
|
1042
|
+
if (!source) return null;
|
|
1018
1043
|
const meta = source.metadata || {};
|
|
1019
1044
|
const field = predicate.field;
|
|
1020
1045
|
const entries = Object.entries(meta)
|
|
@@ -1032,7 +1057,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
1032
1057
|
if (value !== null) return value;
|
|
1033
1058
|
}
|
|
1034
1059
|
|
|
1035
|
-
const contentValue = this.extractNumericValueFromContent(source.content, field);
|
|
1060
|
+
const contentValue = this.extractNumericValueFromContent(source.content ?? '', field);
|
|
1036
1061
|
if (contentValue !== null) return contentValue;
|
|
1037
1062
|
}
|
|
1038
1063
|
|
|
@@ -1046,6 +1071,7 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
1046
1071
|
}
|
|
1047
1072
|
|
|
1048
1073
|
private extractNumericValueFromContent(content: string, field: string): number | null {
|
|
1074
|
+
if (!content || typeof content !== 'string') return null;
|
|
1049
1075
|
const escapedWords = field
|
|
1050
1076
|
.split(/\s+|_+|-+/)
|
|
1051
1077
|
.filter(Boolean)
|
|
@@ -1164,6 +1190,18 @@ You are a helpful assistant. Use the provided context to answer questions accura
|
|
|
1164
1190
|
}
|
|
1165
1191
|
}
|
|
1166
1192
|
|
|
1193
|
+
console.log('[Pipeline] retrieve() response:', {
|
|
1194
|
+
query,
|
|
1195
|
+
namespace: ns,
|
|
1196
|
+
count: resolvedSources.length,
|
|
1197
|
+
sample: resolvedSources.slice(0, 2).map((s) => ({
|
|
1198
|
+
id: s?.id,
|
|
1199
|
+
score: s?.score,
|
|
1200
|
+
contentSnippet: String(s?.content ?? '').substring(0, 150),
|
|
1201
|
+
metadata: s?.metadata,
|
|
1202
|
+
})),
|
|
1203
|
+
});
|
|
1204
|
+
|
|
1167
1205
|
return { sources: resolvedSources, graphData };
|
|
1168
1206
|
}
|
|
1169
1207
|
|
|
@@ -360,10 +360,10 @@ Return ONLY 'vector', 'graph', or 'both'. No explanation.`;
|
|
|
360
360
|
{ temperature: 0, maxTokens: 10 }
|
|
361
361
|
);
|
|
362
362
|
|
|
363
|
-
const cleanResponse = response.trim().toLowerCase();
|
|
364
|
-
if (cleanResponse.includes('vector')) return 'vector';
|
|
365
|
-
if (cleanResponse.includes('graph')) return 'graph';
|
|
363
|
+
const cleanResponse = (response ?? '').trim().toLowerCase();
|
|
366
364
|
if (cleanResponse.includes('both')) return 'both';
|
|
365
|
+
if (cleanResponse.includes('graph')) return 'graph';
|
|
366
|
+
if (cleanResponse.includes('vector')) return 'vector';
|
|
367
367
|
} catch (error) {
|
|
368
368
|
console.warn('[QueryProcessor] LLM strategy classification failed, falling back to keywords:', error);
|
|
369
369
|
}
|