@retrivora-ai/rag-engine 2.0.5 → 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 +268 -66
- package/dist/handlers/index.mjs +268 -66
- package/dist/index.js +79 -22
- package/dist/index.mjs +79 -22
- package/dist/server.js +268 -66
- package/dist/server.mjs +268 -66
- package/package.json +1 -1
- package/src/core/DatabaseStorage.ts +26 -4
- package/src/core/Pipeline.ts +61 -18
- package/src/core/QueryProcessor.ts +3 -3
- package/src/llm/providers/UniversalLLMAdapter.ts +83 -11
- 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.js
CHANGED
|
@@ -4007,7 +4007,7 @@ var UniversalLLMAdapter = class {
|
|
|
4007
4007
|
});
|
|
4008
4008
|
}
|
|
4009
4009
|
async chat(messages, context) {
|
|
4010
|
-
var _a2, _b;
|
|
4010
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
4011
4011
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4012
4012
|
const formattedMessages = [
|
|
4013
4013
|
{ role: "system", content: `${this.systemPrompt}
|
|
@@ -4032,8 +4032,27 @@ ${context != null ? context : "None"}` },
|
|
|
4032
4032
|
temperature: this.temperature
|
|
4033
4033
|
};
|
|
4034
4034
|
}
|
|
4035
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4036
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4037
|
+
const _g2 = globalThis;
|
|
4038
|
+
if (typeof _g2.__retrivoraDispatchChat === "function") {
|
|
4039
|
+
try {
|
|
4040
|
+
const res = await _g2.__retrivoraDispatchChat({
|
|
4041
|
+
model: this.model,
|
|
4042
|
+
messages: formattedMessages,
|
|
4043
|
+
max_tokens: this.maxTokens,
|
|
4044
|
+
temperature: this.temperature
|
|
4045
|
+
}, this.apiKey);
|
|
4046
|
+
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) {
|
|
4047
|
+
return res.response.choices[0].message.content;
|
|
4048
|
+
}
|
|
4049
|
+
} catch (dispatchErr) {
|
|
4050
|
+
throw dispatchErr;
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4035
4054
|
const { data } = await this.http.post(path2, payload);
|
|
4036
|
-
const extractPath = (
|
|
4055
|
+
const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
|
|
4037
4056
|
const result = resolvePath(data, extractPath);
|
|
4038
4057
|
if (result === void 0) {
|
|
4039
4058
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
@@ -4047,7 +4066,7 @@ ${context != null ? context : "None"}` },
|
|
|
4047
4066
|
*/
|
|
4048
4067
|
chatStream(messages, context) {
|
|
4049
4068
|
return __asyncGenerator(this, null, function* () {
|
|
4050
|
-
var _a2, _b, _c;
|
|
4069
|
+
var _a2, _b, _c, _d, _e, _f, _g2;
|
|
4051
4070
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4052
4071
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
4053
4072
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
@@ -4078,19 +4097,46 @@ ${context != null ? context : "None"}` },
|
|
|
4078
4097
|
stream: true
|
|
4079
4098
|
};
|
|
4080
4099
|
}
|
|
4081
|
-
const
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4100
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4101
|
+
let streamBody = null;
|
|
4102
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4103
|
+
const _g3 = globalThis;
|
|
4104
|
+
if (typeof _g3.__retrivoraDispatchChat === "function") {
|
|
4105
|
+
try {
|
|
4106
|
+
const res = yield new __await(_g3.__retrivoraDispatchChat({
|
|
4107
|
+
model: this.model,
|
|
4108
|
+
messages: formattedMessages,
|
|
4109
|
+
max_tokens: this.maxTokens,
|
|
4110
|
+
temperature: this.temperature,
|
|
4111
|
+
stream: true
|
|
4112
|
+
}, this.apiKey));
|
|
4113
|
+
if (res == null ? void 0 : res.stream) {
|
|
4114
|
+
streamBody = res.stream;
|
|
4115
|
+
} else if ((_f = (_e = (_d = (_c = res == null ? void 0 : res.response) == null ? void 0 : _c.choices) == null ? void 0 : _d[0]) == null ? void 0 : _e.message) == null ? void 0 : _f.content) {
|
|
4116
|
+
yield res.response.choices[0].message.content;
|
|
4117
|
+
return;
|
|
4118
|
+
}
|
|
4119
|
+
} catch (dispatchErr) {
|
|
4120
|
+
throw dispatchErr;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4089
4123
|
}
|
|
4090
|
-
if (!
|
|
4091
|
-
|
|
4124
|
+
if (!streamBody) {
|
|
4125
|
+
const response = yield new __await(fetch(url, {
|
|
4126
|
+
method: "POST",
|
|
4127
|
+
headers: this.resolvedHeaders,
|
|
4128
|
+
body: JSON.stringify(payload)
|
|
4129
|
+
}));
|
|
4130
|
+
if (!response.ok) {
|
|
4131
|
+
const errorText = yield new __await(response.text().catch(() => response.statusText));
|
|
4132
|
+
throw new Error(`[UniversalLLMAdapter] Streaming request failed (${response.status}): ${errorText}`);
|
|
4133
|
+
}
|
|
4134
|
+
if (!response.body) {
|
|
4135
|
+
throw new Error("[UniversalLLMAdapter] Response body is null \u2014 server did not send a streaming response.");
|
|
4136
|
+
}
|
|
4137
|
+
streamBody = response.body;
|
|
4092
4138
|
}
|
|
4093
|
-
const reader =
|
|
4139
|
+
const reader = streamBody.getReader();
|
|
4094
4140
|
const decoder = new TextDecoder("utf-8");
|
|
4095
4141
|
let buffer = "";
|
|
4096
4142
|
try {
|
|
@@ -4099,7 +4145,7 @@ ${context != null ? context : "None"}` },
|
|
|
4099
4145
|
if (done) break;
|
|
4100
4146
|
buffer += decoder.decode(value, { stream: true });
|
|
4101
4147
|
const lines = buffer.split("\n");
|
|
4102
|
-
buffer = (
|
|
4148
|
+
buffer = (_g2 = lines.pop()) != null ? _g2 : "";
|
|
4103
4149
|
for (const line of lines) {
|
|
4104
4150
|
const trimmed = line.trim();
|
|
4105
4151
|
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
@@ -4127,7 +4173,7 @@ ${context != null ? context : "None"}` },
|
|
|
4127
4173
|
});
|
|
4128
4174
|
}
|
|
4129
4175
|
async embed(text) {
|
|
4130
|
-
var _a2, _b;
|
|
4176
|
+
var _a2, _b, _c, _d;
|
|
4131
4177
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
4132
4178
|
let payload;
|
|
4133
4179
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -4141,8 +4187,25 @@ ${context != null ? context : "None"}` },
|
|
|
4141
4187
|
input: text
|
|
4142
4188
|
};
|
|
4143
4189
|
}
|
|
4190
|
+
const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
|
|
4191
|
+
if (isSelfHost || Boolean(process.env.VERCEL)) {
|
|
4192
|
+
const _g2 = globalThis;
|
|
4193
|
+
if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
|
|
4194
|
+
try {
|
|
4195
|
+
const res = await _g2.__retrivoraDispatchEmbedding({
|
|
4196
|
+
model: this.model,
|
|
4197
|
+
input: text
|
|
4198
|
+
}, this.apiKey);
|
|
4199
|
+
if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
|
|
4200
|
+
return res.data[0].embedding;
|
|
4201
|
+
}
|
|
4202
|
+
} catch (dispatchErr) {
|
|
4203
|
+
throw dispatchErr;
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4144
4207
|
const { data } = await this.http.post(path2, payload);
|
|
4145
|
-
const extractPath = (
|
|
4208
|
+
const extractPath = (_d = this.opts.embedExtractPath) != null ? _d : "data[0].embedding";
|
|
4146
4209
|
const vector = resolvePath(data, extractPath);
|
|
4147
4210
|
if (!Array.isArray(vector)) {
|
|
4148
4211
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
@@ -4731,7 +4794,8 @@ var Reranker = class {
|
|
|
4731
4794
|
return matches.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
4732
4795
|
}
|
|
4733
4796
|
const scoredMatches = matches.map((match) => {
|
|
4734
|
-
|
|
4797
|
+
var _a2;
|
|
4798
|
+
const contentLower = ((_a2 = match == null ? void 0 : match.content) != null ? _a2 : "").toLowerCase();
|
|
4735
4799
|
let keywordScore = 0;
|
|
4736
4800
|
keywords.forEach((keyword) => {
|
|
4737
4801
|
if (contentLower.includes(keyword)) {
|
|
@@ -4752,7 +4816,10 @@ var Reranker = class {
|
|
|
4752
4816
|
[{ role: "user", content: `Query: "${query}"
|
|
4753
4817
|
|
|
4754
4818
|
Documents:
|
|
4755
|
-
${topN.map((m, i) =>
|
|
4819
|
+
${topN.map((m, i) => {
|
|
4820
|
+
var _a2;
|
|
4821
|
+
return `[${i}] ${((_a2 = m == null ? void 0 : m.content) != null ? _a2 : "").replace(/\n/g, " ")}`;
|
|
4822
|
+
}).join("\n")}` }],
|
|
4756
4823
|
"",
|
|
4757
4824
|
{
|
|
4758
4825
|
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.',
|
|
@@ -5923,10 +5990,10 @@ Return ONLY 'vector', 'graph', or 'both'. No explanation.`;
|
|
|
5923
5990
|
"",
|
|
5924
5991
|
{ temperature: 0, maxTokens: 10 }
|
|
5925
5992
|
);
|
|
5926
|
-
const cleanResponse = response.trim().toLowerCase();
|
|
5927
|
-
if (cleanResponse.includes("vector")) return "vector";
|
|
5928
|
-
if (cleanResponse.includes("graph")) return "graph";
|
|
5993
|
+
const cleanResponse = (response != null ? response : "").trim().toLowerCase();
|
|
5929
5994
|
if (cleanResponse.includes("both")) return "both";
|
|
5995
|
+
if (cleanResponse.includes("graph")) return "graph";
|
|
5996
|
+
if (cleanResponse.includes("vector")) return "vector";
|
|
5930
5997
|
} catch (error) {
|
|
5931
5998
|
console.warn("[QueryProcessor] LLM strategy classification failed, falling back to keywords:", error);
|
|
5932
5999
|
}
|
|
@@ -6100,7 +6167,10 @@ var IntentClassifier = class {
|
|
|
6100
6167
|
hasCategoricalFields = catKeys.size > 0;
|
|
6101
6168
|
numericFieldCount = numericKeys.size;
|
|
6102
6169
|
categoricalFieldCount = catKeys.size;
|
|
6103
|
-
if (productKeyMatches >= 2 || docs.some((d) =>
|
|
6170
|
+
if (productKeyMatches >= 2 || docs.some((d) => {
|
|
6171
|
+
var _a2, _b;
|
|
6172
|
+
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");
|
|
6173
|
+
})) {
|
|
6104
6174
|
isProductLike = true;
|
|
6105
6175
|
}
|
|
6106
6176
|
}
|
|
@@ -6380,7 +6450,10 @@ var TextRendererStrategy = class {
|
|
|
6380
6450
|
return { type: "text", title, data: { content: data } };
|
|
6381
6451
|
}
|
|
6382
6452
|
const docs = Array.isArray(data) ? data : [];
|
|
6383
|
-
const text = docs.map((d) =>
|
|
6453
|
+
const text = docs.map((d) => {
|
|
6454
|
+
var _a2;
|
|
6455
|
+
return (_a2 = d == null ? void 0 : d.content) != null ? _a2 : "";
|
|
6456
|
+
}).join("\n\n");
|
|
6384
6457
|
return { type: "text", title, data: { content: text || "No detailed content available." } };
|
|
6385
6458
|
}
|
|
6386
6459
|
};
|
|
@@ -6637,6 +6710,19 @@ var UITransformer = class _UITransformer {
|
|
|
6637
6710
|
if (!retrievedData || retrievedData.length === 0) {
|
|
6638
6711
|
return this.createTextResponse("No data available", "No relevant data found for your query.");
|
|
6639
6712
|
}
|
|
6713
|
+
console.log("[UITransformer.transform] Processing retrievedData:", {
|
|
6714
|
+
userQuery,
|
|
6715
|
+
retrievedCount: retrievedData.length,
|
|
6716
|
+
sample: retrievedData.slice(0, 2).map((item) => {
|
|
6717
|
+
var _a3;
|
|
6718
|
+
return {
|
|
6719
|
+
id: item == null ? void 0 : item.id,
|
|
6720
|
+
contentType: typeof (item == null ? void 0 : item.content),
|
|
6721
|
+
contentSnippet: String((_a3 = item == null ? void 0 : item.content) != null ? _a3 : "").substring(0, 150),
|
|
6722
|
+
metadataKeys: Object.keys((item == null ? void 0 : item.metadata) || {})
|
|
6723
|
+
};
|
|
6724
|
+
})
|
|
6725
|
+
});
|
|
6640
6726
|
const resolvedIntent = intent != null ? intent : this.detectIntentHeuristic(userQuery);
|
|
6641
6727
|
const filteredData = resolvedIntent.filterInStockOnly ? retrievedData.filter((item) => this.determineStockStatus(item)) : retrievedData;
|
|
6642
6728
|
const profile = this.profileData(filteredData);
|
|
@@ -7126,7 +7212,10 @@ ${schemaProfileText}` : ""}`;
|
|
|
7126
7212
|
type: "radar_chart",
|
|
7127
7213
|
title: "Product Comparison",
|
|
7128
7214
|
description: `Comparing ${data.length} items across ${radarData.length} attributes`,
|
|
7129
|
-
data: radarData.length > 0 ? radarData : data.map((d) =>
|
|
7215
|
+
data: radarData.length > 0 ? radarData : data.map((d) => {
|
|
7216
|
+
var _a2;
|
|
7217
|
+
return { attribute: ((_a2 = d == null ? void 0 : d.content) != null ? _a2 : "").substring(0, 40) };
|
|
7218
|
+
})
|
|
7130
7219
|
};
|
|
7131
7220
|
}
|
|
7132
7221
|
static transformToTable(data, query = "") {
|
|
@@ -7143,7 +7232,10 @@ ${schemaProfileText}` : ""}`;
|
|
|
7143
7232
|
static transformToText(data) {
|
|
7144
7233
|
return this.createTextResponse(
|
|
7145
7234
|
"Retrieved Context",
|
|
7146
|
-
data.map((item) =>
|
|
7235
|
+
data.map((item) => {
|
|
7236
|
+
var _a2;
|
|
7237
|
+
return (_a2 = item == null ? void 0 : item.content) != null ? _a2 : "";
|
|
7238
|
+
}).join("\n\n"),
|
|
7147
7239
|
`Found ${data.length} relevant results`
|
|
7148
7240
|
);
|
|
7149
7241
|
}
|
|
@@ -7304,6 +7396,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
7304
7396
|
return productTerms && productAction && !nonProductEntityTerms;
|
|
7305
7397
|
}
|
|
7306
7398
|
static isProductData(item) {
|
|
7399
|
+
if (!item) return false;
|
|
7307
7400
|
const content = (item.content || "").toLowerCase();
|
|
7308
7401
|
const productKeywords = [
|
|
7309
7402
|
"product",
|
|
@@ -7562,12 +7655,12 @@ ${schemaProfileText}` : ""}`;
|
|
|
7562
7655
|
}
|
|
7563
7656
|
static extractTimeSeriesData(data) {
|
|
7564
7657
|
return data.map((item) => {
|
|
7565
|
-
var _a2, _b, _c, _d, _e;
|
|
7658
|
+
var _a2, _b, _c, _d, _e, _f;
|
|
7566
7659
|
const meta = item.metadata || {};
|
|
7567
7660
|
return {
|
|
7568
7661
|
timestamp: (_b = (_a2 = meta.timestamp) != null ? _a2 : meta.date) != null ? _b : (/* @__PURE__ */ new Date()).toISOString(),
|
|
7569
7662
|
value: (_d = (_c = meta.value) != null ? _c : item.score) != null ? _d : 0,
|
|
7570
|
-
label: (
|
|
7663
|
+
label: (_f = meta.label) != null ? _f : ((_e = item == null ? void 0 : item.content) != null ? _e : "").substring(0, 50)
|
|
7571
7664
|
};
|
|
7572
7665
|
});
|
|
7573
7666
|
}
|
|
@@ -7681,7 +7774,8 @@ ${schemaProfileText}` : ""}`;
|
|
|
7681
7774
|
}, query.includes(normalizedField) ? 3 : 0);
|
|
7682
7775
|
}
|
|
7683
7776
|
static resolveTableCellValue(item, column) {
|
|
7684
|
-
|
|
7777
|
+
var _a2, _b, _c;
|
|
7778
|
+
if (column === "Content") return ((_a2 = item == null ? void 0 : item.content) != null ? _a2 : "").substring(0, 100);
|
|
7685
7779
|
const meta = item.metadata || {};
|
|
7686
7780
|
const normalizedColumn = this.normalizeComparableField(column);
|
|
7687
7781
|
const exactMetadata = Object.entries(meta).find(
|
|
@@ -7692,9 +7786,9 @@ ${schemaProfileText}` : ""}`;
|
|
|
7692
7786
|
}
|
|
7693
7787
|
const aliasValue = this.resolveAliasedTableCell(meta, column);
|
|
7694
7788
|
if (aliasValue !== void 0) return this.toDisplayValue(aliasValue);
|
|
7695
|
-
const contentValue = this.extractContentFieldValue(item.content, column);
|
|
7789
|
+
const contentValue = this.extractContentFieldValue((_b = item == null ? void 0 : item.content) != null ? _b : "", column);
|
|
7696
7790
|
if (contentValue !== null) return contentValue;
|
|
7697
|
-
const aliasContentValue = this.extractAliasedContentFieldValue(item.content, column);
|
|
7791
|
+
const aliasContentValue = this.extractAliasedContentFieldValue((_c = item == null ? void 0 : item.content) != null ? _c : "", column);
|
|
7698
7792
|
return aliasContentValue != null ? aliasContentValue : "";
|
|
7699
7793
|
}
|
|
7700
7794
|
static resolveAliasedTableCell(meta, column) {
|
|
@@ -7744,6 +7838,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
7744
7838
|
return { inStockCount: inStock, outOfStockCount: outOfStock };
|
|
7745
7839
|
}
|
|
7746
7840
|
static determineStockStatus(item) {
|
|
7841
|
+
if (!item) return true;
|
|
7747
7842
|
const meta = item.metadata || {};
|
|
7748
7843
|
const stockValue = resolveMetadataValue(meta, "stock");
|
|
7749
7844
|
if (stockValue !== void 0) {
|
|
@@ -7789,35 +7884,64 @@ ${schemaProfileText}` : ""}`;
|
|
|
7789
7884
|
return resolveMetadataValue(meta, uiKey);
|
|
7790
7885
|
}
|
|
7791
7886
|
static extractProductInfo(item, config, trainedSchema) {
|
|
7792
|
-
var _a2;
|
|
7887
|
+
var _a2, _b;
|
|
7888
|
+
if (!item) return null;
|
|
7793
7889
|
const meta = item.metadata || {};
|
|
7890
|
+
const content = item.content || "";
|
|
7794
7891
|
const name = this.getDynamicVal(meta, "name", config, trainedSchema);
|
|
7795
7892
|
const price = this.getDynamicVal(meta, "price", config, trainedSchema);
|
|
7796
7893
|
const brand = this.getDynamicVal(meta, "brand", config, trainedSchema);
|
|
7797
7894
|
const description = this.cleanProductDescription(
|
|
7798
|
-
(_a2 = this.extractProductDescriptionFromContent(
|
|
7895
|
+
(_a2 = this.extractProductDescriptionFromContent(content)) != null ? _a2 : this.getProductDescriptionValue(meta, config, trainedSchema)
|
|
7799
7896
|
);
|
|
7800
7897
|
if (name || this.isProductData(item)) {
|
|
7801
7898
|
let finalName = name ? String(name) : void 0;
|
|
7899
|
+
if (!finalName && content) {
|
|
7900
|
+
const nameMatch = content.match(/(?:Product|Item|Name):\s*([^\n]+)/i);
|
|
7901
|
+
finalName = nameMatch ? nameMatch[1].trim() : (_b = content.split("\n")[0]) == null ? void 0 : _b.substring(0, 60);
|
|
7902
|
+
}
|
|
7802
7903
|
if (!finalName) {
|
|
7803
|
-
|
|
7804
|
-
|
|
7904
|
+
console.warn(
|
|
7905
|
+
`[UITransformer] Unable to read product name from metadata or content for item ${item.id}. Defaulting to 'Unnamed Product'.`,
|
|
7906
|
+
{ metadataKeys: Object.keys(meta), contentLength: content.length }
|
|
7907
|
+
);
|
|
7805
7908
|
}
|
|
7806
7909
|
let finalPrice = typeof price === "number" || typeof price === "string" ? price : void 0;
|
|
7807
|
-
if (!finalPrice) {
|
|
7808
|
-
const priceMatch =
|
|
7910
|
+
if (!finalPrice && content) {
|
|
7911
|
+
const priceMatch = content.match(/(?:Price|Cost):\s*\$?([\d,.]+)/i) || content.match(/\$\s*([\d,.]+)/);
|
|
7809
7912
|
if (priceMatch) finalPrice = priceMatch[1].replace(/,/g, "");
|
|
7810
7913
|
}
|
|
7914
|
+
if (finalPrice === void 0) {
|
|
7915
|
+
console.warn(
|
|
7916
|
+
`[UITransformer] Unable to read product price from metadata or content for item ${item.id}.`,
|
|
7917
|
+
{ metadataKeys: Object.keys(meta), contentSnippet: content.substring(0, 100) }
|
|
7918
|
+
);
|
|
7919
|
+
}
|
|
7811
7920
|
const imageValue = this.getDynamicVal(meta, "image", config, trainedSchema);
|
|
7921
|
+
if (!imageValue) {
|
|
7922
|
+
console.debug(
|
|
7923
|
+
`[UITransformer] Unable to read product image URL from metadata for item ${item.id}.`
|
|
7924
|
+
);
|
|
7925
|
+
}
|
|
7926
|
+
if (!description) {
|
|
7927
|
+
console.debug(
|
|
7928
|
+
`[UITransformer] Unable to read product description from metadata or content for item ${item.id}.`
|
|
7929
|
+
);
|
|
7930
|
+
}
|
|
7812
7931
|
return {
|
|
7813
7932
|
id: item.id,
|
|
7814
|
-
name: finalName,
|
|
7933
|
+
name: finalName || "Unnamed Product",
|
|
7815
7934
|
price: finalPrice,
|
|
7816
7935
|
image: typeof imageValue === "string" ? imageValue : void 0,
|
|
7817
7936
|
brand: brand ? String(brand) : void 0,
|
|
7818
7937
|
description,
|
|
7819
7938
|
inStock: this.determineStockStatus(item)
|
|
7820
7939
|
};
|
|
7940
|
+
} else {
|
|
7941
|
+
console.warn(
|
|
7942
|
+
`[UITransformer] Item ${item.id} skipped: unable to read name or identify as product data from metadata/content.`,
|
|
7943
|
+
{ metadataKeys: Object.keys(meta), contentSnippet: content.substring(0, 100) }
|
|
7944
|
+
);
|
|
7821
7945
|
}
|
|
7822
7946
|
return null;
|
|
7823
7947
|
}
|
|
@@ -7902,13 +8026,13 @@ RULES:
|
|
|
7902
8026
|
5. If no relevant data is found, return text: "I cannot answer this question based on the available information."`;
|
|
7903
8027
|
}
|
|
7904
8028
|
static buildContextSummary(sources, maxChars = 6e3) {
|
|
7905
|
-
const items = sources.map((s, i) => {
|
|
8029
|
+
const items = (sources || []).filter(Boolean).map((s, i) => {
|
|
7906
8030
|
var _a2, _b, _c, _d;
|
|
7907
8031
|
return {
|
|
7908
8032
|
index: i + 1,
|
|
7909
|
-
content: (_b = (_a2 = s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
7910
|
-
metadata: (_c = s.metadata) != null ? _c : {},
|
|
7911
|
-
score: (_d = s.score) != null ? _d : 0
|
|
8033
|
+
content: (_b = (_a2 = s == null ? void 0 : s.content) == null ? void 0 : _a2.substring(0, 400)) != null ? _b : "",
|
|
8034
|
+
metadata: (_c = s == null ? void 0 : s.metadata) != null ? _c : {},
|
|
8035
|
+
score: (_d = s == null ? void 0 : s.score) != null ? _d : 0
|
|
7912
8036
|
};
|
|
7913
8037
|
});
|
|
7914
8038
|
const full = JSON.stringify(items, null, 2);
|
|
@@ -8477,35 +8601,74 @@ ${m.content}`).join("\n\n---\n\n");
|
|
|
8477
8601
|
const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
|
|
8478
8602
|
const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
|
|
8479
8603
|
const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
|
|
8480
|
-
const rawSources = (strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : [];
|
|
8604
|
+
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"));
|
|
8605
|
+
console.log("[Pipeline] Raw vectorDB.query response:", {
|
|
8606
|
+
rawCount: rawSources.length,
|
|
8607
|
+
sample: rawSources.slice(0, 2).map((s) => {
|
|
8608
|
+
var _a3;
|
|
8609
|
+
return {
|
|
8610
|
+
id: s == null ? void 0 : s.id,
|
|
8611
|
+
score: s == null ? void 0 : s.score,
|
|
8612
|
+
contentType: typeof (s == null ? void 0 : s.content),
|
|
8613
|
+
contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
|
|
8614
|
+
metadataKeys: Object.keys((s == null ? void 0 : s.metadata) || {})
|
|
8615
|
+
};
|
|
8616
|
+
})
|
|
8617
|
+
});
|
|
8481
8618
|
const retrieveEnd = performance.now();
|
|
8482
8619
|
const embedMs = retrieveEnd - embedStart;
|
|
8483
8620
|
const retrieveMs = retrieveEnd - embedStart;
|
|
8484
8621
|
const rerankStart = performance.now();
|
|
8485
|
-
const structuredSources = this.applyStructuredFilters(rawSources, filter);
|
|
8486
|
-
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) =>
|
|
8622
|
+
const structuredSources = this.applyStructuredFilters(rawSources, filter).filter((s) => Boolean(s && typeof s === "object"));
|
|
8623
|
+
let fullSources = hasNumericPredicates ? structuredSources : structuredSources.filter((m) => {
|
|
8624
|
+
var _a3;
|
|
8625
|
+
return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= scoreThreshold;
|
|
8626
|
+
});
|
|
8487
8627
|
const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
|
|
8488
8628
|
const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
|
|
8489
8629
|
if (!hasNumericPredicates && useReranking) {
|
|
8490
|
-
fullSources = yield new __await(this.reranker.rerank(fullSources, question, rerankLimit));
|
|
8630
|
+
fullSources = (yield new __await(this.reranker.rerank(fullSources, question, rerankLimit))).filter((s) => Boolean(s && typeof s === "object"));
|
|
8491
8631
|
} else if (!wantsExhaustiveList) {
|
|
8492
8632
|
fullSources = fullSources.slice(0, topK);
|
|
8493
8633
|
}
|
|
8494
8634
|
const rerankMs = performance.now() - rerankStart;
|
|
8495
|
-
let context = fullSources.length ? fullSources.map((m, i) =>
|
|
8496
|
-
|
|
8635
|
+
let context = fullSources.length ? fullSources.map((m, i) => {
|
|
8636
|
+
var _a3;
|
|
8637
|
+
return `[Source ${i + 1}]
|
|
8638
|
+
${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
|
|
8639
|
+
}).join("\n\n---\n\n") : "No relevant context found.";
|
|
8497
8640
|
let displayCount = 15;
|
|
8498
8641
|
if (hasMetadataFilter) {
|
|
8499
8642
|
displayCount = fullSources.length;
|
|
8500
8643
|
} else {
|
|
8501
8644
|
const baseThreshold = Math.max(scoreThreshold, 0.4);
|
|
8502
|
-
const highlyRelevant = fullSources.filter((m) =>
|
|
8645
|
+
const highlyRelevant = fullSources.filter((m) => {
|
|
8646
|
+
var _a3;
|
|
8647
|
+
return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= baseThreshold;
|
|
8648
|
+
});
|
|
8503
8649
|
displayCount = Math.max(highlyRelevant.length, topK);
|
|
8504
8650
|
if (displayCount > 15) {
|
|
8505
8651
|
displayCount = 15;
|
|
8506
8652
|
}
|
|
8507
8653
|
}
|
|
8508
|
-
const sources = [...fullSources].
|
|
8654
|
+
const sources = [...fullSources].filter((s) => Boolean(s && typeof s === "object")).sort((a, b) => {
|
|
8655
|
+
var _a3, _b2;
|
|
8656
|
+
return ((_a3 = b == null ? void 0 : b.score) != null ? _a3 : 0) - ((_b2 = a == null ? void 0 : a.score) != null ? _b2 : 0);
|
|
8657
|
+
}).slice(0, displayCount);
|
|
8658
|
+
console.log("[Pipeline] Final sources for prompt & UI:", {
|
|
8659
|
+
count: sources.length,
|
|
8660
|
+
sources: sources.map((s, idx) => {
|
|
8661
|
+
var _a3;
|
|
8662
|
+
return {
|
|
8663
|
+
rank: idx + 1,
|
|
8664
|
+
id: s == null ? void 0 : s.id,
|
|
8665
|
+
score: s == null ? void 0 : s.score,
|
|
8666
|
+
contentType: typeof (s == null ? void 0 : s.content),
|
|
8667
|
+
contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
|
|
8668
|
+
metadata: s == null ? void 0 : s.metadata
|
|
8669
|
+
};
|
|
8670
|
+
})
|
|
8671
|
+
});
|
|
8509
8672
|
if (graphData && graphData.nodes.length > 0) {
|
|
8510
8673
|
const graphContext = graphData.nodes.map(
|
|
8511
8674
|
(n) => `Entity: ${n.label} (${n.id})${n.properties ? " - " + JSON.stringify(n.properties) : ""}`
|
|
@@ -8531,18 +8694,18 @@ ${context}`;
|
|
|
8531
8694
|
}
|
|
8532
8695
|
yield {
|
|
8533
8696
|
reply: "",
|
|
8534
|
-
sources: sources.map((s) => {
|
|
8535
|
-
var _a3;
|
|
8697
|
+
sources: (sources || []).filter((s) => Boolean(s && typeof s === "object")).map((s) => {
|
|
8698
|
+
var _a3, _b2, _c2;
|
|
8536
8699
|
return {
|
|
8537
8700
|
id: s.id,
|
|
8538
|
-
score: s.score,
|
|
8539
|
-
content: s.content,
|
|
8540
|
-
metadata: (
|
|
8701
|
+
score: (_a3 = s.score) != null ? _a3 : 0,
|
|
8702
|
+
content: (_b2 = s == null ? void 0 : s.content) != null ? _b2 : "",
|
|
8703
|
+
metadata: (_c2 = s == null ? void 0 : s.metadata) != null ? _c2 : {},
|
|
8541
8704
|
namespace: ns
|
|
8542
8705
|
};
|
|
8543
8706
|
})
|
|
8544
8707
|
};
|
|
8545
|
-
const allMetadataKeys = Array.from(new Set(sources.flatMap((s) => Object.keys(s.metadata || {}))));
|
|
8708
|
+
const allMetadataKeys = Array.from(new Set(sources.filter(Boolean).flatMap((s) => Object.keys((s == null ? void 0 : s.metadata) || {}))));
|
|
8546
8709
|
const cachedSchema = allMetadataKeys.length > 0 ? SchemaMapper.getCached(ns, allMetadataKeys) : void 0;
|
|
8547
8710
|
if (allMetadataKeys.length > 0 && !cachedSchema) {
|
|
8548
8711
|
SchemaMapper.train(this.llmProvider, ns, allMetadataKeys).catch(() => {
|
|
@@ -8577,7 +8740,10 @@ ${context}`;
|
|
|
8577
8740
|
if (isSimulatedThinking) {
|
|
8578
8741
|
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.`)";
|
|
8579
8742
|
}
|
|
8580
|
-
const hardenedHistory = [
|
|
8743
|
+
const hardenedHistory = (Array.isArray(history) ? history : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
8744
|
+
role: m.role || "user",
|
|
8745
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
8746
|
+
}));
|
|
8581
8747
|
const userQuestion = { role: "user", content: question + finalRestrictionSuffix };
|
|
8582
8748
|
const messages = [...hardenedHistory, userQuestion];
|
|
8583
8749
|
const systemPrompt = (_v = this.config.llm.systemPrompt) != null ? _v : "";
|
|
@@ -8724,13 +8890,13 @@ ${context}`;
|
|
|
8724
8890
|
rewrittenQuery,
|
|
8725
8891
|
systemPrompt,
|
|
8726
8892
|
userPrompt: question + finalRestrictionSuffix,
|
|
8727
|
-
chunks: sources.map((s) => {
|
|
8728
|
-
var _a3;
|
|
8893
|
+
chunks: (sources || []).filter(Boolean).map((s) => {
|
|
8894
|
+
var _a3, _b2;
|
|
8729
8895
|
return {
|
|
8730
8896
|
id: s.id,
|
|
8731
8897
|
score: s.score,
|
|
8732
|
-
content: s.content,
|
|
8733
|
-
metadata: (
|
|
8898
|
+
content: (_a3 = s == null ? void 0 : s.content) != null ? _a3 : "",
|
|
8899
|
+
metadata: (_b2 = s == null ? void 0 : s.metadata) != null ? _b2 : {},
|
|
8734
8900
|
namespace: ns
|
|
8735
8901
|
};
|
|
8736
8902
|
}),
|
|
@@ -8831,6 +8997,8 @@ ${context}`;
|
|
|
8831
8997
|
});
|
|
8832
8998
|
}
|
|
8833
8999
|
resolveNumericPredicateValue(source, predicate) {
|
|
9000
|
+
var _a2;
|
|
9001
|
+
if (!source) return null;
|
|
8834
9002
|
const meta = source.metadata || {};
|
|
8835
9003
|
const field = predicate.field;
|
|
8836
9004
|
const entries = Object.entries(meta).filter(([, value]) => value !== null && value !== void 0 && typeof value !== "object");
|
|
@@ -8842,7 +9010,7 @@ ${context}`;
|
|
|
8842
9010
|
const value = this.toFiniteNumber(Array.isArray(fuzzy) ? fuzzy[1] : fuzzy.value);
|
|
8843
9011
|
if (value !== null) return value;
|
|
8844
9012
|
}
|
|
8845
|
-
const contentValue = this.extractNumericValueFromContent(source.content, field);
|
|
9013
|
+
const contentValue = this.extractNumericValueFromContent((_a2 = source.content) != null ? _a2 : "", field);
|
|
8846
9014
|
if (contentValue !== null) return contentValue;
|
|
8847
9015
|
}
|
|
8848
9016
|
for (const [key, value] of entries) {
|
|
@@ -8853,6 +9021,7 @@ ${context}`;
|
|
|
8853
9021
|
return null;
|
|
8854
9022
|
}
|
|
8855
9023
|
extractNumericValueFromContent(content, field) {
|
|
9024
|
+
if (!content || typeof content !== "string") return null;
|
|
8856
9025
|
const escapedWords = field.split(/\s+|_+|-+/).filter(Boolean).map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
8857
9026
|
if (escapedWords.length === 0) return null;
|
|
8858
9027
|
const pattern = new RegExp(`(?:${escapedWords.join("[\\\\s_:-]*")})\\s*[:\\-\u2013]?\\s*([\\d,]+(?:\\.\\d+)?)`, "i");
|
|
@@ -8938,6 +9107,20 @@ ${context}`;
|
|
|
8938
9107
|
resolvedSources.push(source);
|
|
8939
9108
|
}
|
|
8940
9109
|
}
|
|
9110
|
+
console.log("[Pipeline] retrieve() response:", {
|
|
9111
|
+
query,
|
|
9112
|
+
namespace: ns,
|
|
9113
|
+
count: resolvedSources.length,
|
|
9114
|
+
sample: resolvedSources.slice(0, 2).map((s) => {
|
|
9115
|
+
var _a3;
|
|
9116
|
+
return {
|
|
9117
|
+
id: s == null ? void 0 : s.id,
|
|
9118
|
+
score: s == null ? void 0 : s.score,
|
|
9119
|
+
contentSnippet: String((_a3 = s == null ? void 0 : s.content) != null ? _a3 : "").substring(0, 150),
|
|
9120
|
+
metadata: s == null ? void 0 : s.metadata
|
|
9121
|
+
};
|
|
9122
|
+
})
|
|
9123
|
+
});
|
|
8941
9124
|
return { sources: resolvedSources, graphData };
|
|
8942
9125
|
}
|
|
8943
9126
|
/** Rewrite the user query for better retrieval performance. */
|
|
@@ -9631,6 +9814,7 @@ var import_server = require("next/server");
|
|
|
9631
9814
|
// src/core/DatabaseStorage.ts
|
|
9632
9815
|
var fs = __toESM(require("fs"));
|
|
9633
9816
|
var path = __toESM(require("path"));
|
|
9817
|
+
var os = __toESM(require("os"));
|
|
9634
9818
|
var DatabaseStorage = class {
|
|
9635
9819
|
constructor(config) {
|
|
9636
9820
|
// Dynamic PG Pool
|
|
@@ -9639,7 +9823,8 @@ var DatabaseStorage = class {
|
|
|
9639
9823
|
this.mongoClient = null;
|
|
9640
9824
|
this.mongoDbName = "";
|
|
9641
9825
|
// Filesystem fallback configuration
|
|
9642
|
-
this.
|
|
9826
|
+
this.isServerless = Boolean(process.env.VERCEL || process.env.AWS_LAMBDA_FUNCTION_NAME || process.env.LAMBDA_TASK_ROOT);
|
|
9827
|
+
this.fallbackDir = this.isServerless ? path.join(os.tmpdir(), ".retrivora") : path.join(process.cwd(), ".retrivora");
|
|
9643
9828
|
this.historyFile = path.join(this.fallbackDir, "history.json");
|
|
9644
9829
|
this.feedbackFile = path.join(this.fallbackDir, "feedback.json");
|
|
9645
9830
|
var _a2, _b, _c, _d, _e;
|
|
@@ -9769,10 +9954,27 @@ var DatabaseStorage = class {
|
|
|
9769
9954
|
}
|
|
9770
9955
|
// Helper for FS fallback writes
|
|
9771
9956
|
writeLocalFile(filePath, data) {
|
|
9772
|
-
|
|
9773
|
-
|
|
9957
|
+
try {
|
|
9958
|
+
const dir = path.dirname(filePath);
|
|
9959
|
+
if (!fs.existsSync(dir)) {
|
|
9960
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
9961
|
+
}
|
|
9962
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9963
|
+
} catch (err) {
|
|
9964
|
+
if (err.code === "EROFS") {
|
|
9965
|
+
try {
|
|
9966
|
+
const tmpDir = path.join(os.tmpdir(), ".retrivora");
|
|
9967
|
+
if (!fs.existsSync(tmpDir)) {
|
|
9968
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
9969
|
+
}
|
|
9970
|
+
const tmpFilePath = path.join(tmpDir, path.basename(filePath));
|
|
9971
|
+
fs.writeFileSync(tmpFilePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9972
|
+
} catch (e) {
|
|
9973
|
+
}
|
|
9974
|
+
} else {
|
|
9975
|
+
console.warn(`[DatabaseStorage] Failed to write local fallback file: ${err.message}`);
|
|
9976
|
+
}
|
|
9774
9977
|
}
|
|
9775
|
-
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
9776
9978
|
}
|
|
9777
9979
|
// ─── Message History Operations ──────────────────────────────────────────
|
|
9778
9980
|
async saveMessage(sessionId, message) {
|