@retrivora-ai/rag-engine 2.0.8 → 2.1.1
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 +73 -37
- package/dist/handlers/index.mjs +73 -37
- package/dist/index.js +19 -12
- package/dist/index.mjs +19 -12
- package/dist/server.js +73 -37
- package/dist/server.mjs +73 -37
- package/package.json +1 -1
- package/src/components/ChatWindow.tsx +22 -22
- package/src/core/Pipeline.ts +3 -3
- package/src/llm/providers/GeminiProvider.ts +4 -4
- package/src/llm/providers/GroqProvider.ts +16 -8
- package/src/llm/providers/OpenAIProvider.ts +16 -8
- package/src/llm/providers/QwenProvider.ts +16 -8
- package/src/llm/providers/UniversalLLMAdapter.ts +16 -2
- package/src/rendering/IntentClassifier.ts +3 -3
- package/src/rendering/rules/Rule1SpecificInfoRule.ts +1 -1
- package/src/utils/ProductExtractor.ts +4 -3
- package/src/utils/UITransformer.ts +12 -0
package/dist/index.mjs
CHANGED
|
@@ -1741,32 +1741,31 @@ function isLikelyUiOnlyMessage(text) {
|
|
|
1741
1741
|
}
|
|
1742
1742
|
function extractProductsFromSources(sources, isUser) {
|
|
1743
1743
|
if (isUser || !sources) return [];
|
|
1744
|
-
return sources.filter((s) => {
|
|
1745
|
-
var _a;
|
|
1744
|
+
return sources.filter((s) => Boolean(s && typeof s === "object")).filter((s) => {
|
|
1745
|
+
var _a, _b;
|
|
1746
1746
|
const m = (_a = s.metadata) != null ? _a : {};
|
|
1747
1747
|
const keys = Object.keys(m).map((k) => k.toLowerCase());
|
|
1748
1748
|
const hasStrongProductKey = keys.some(
|
|
1749
1749
|
(k) => ["price", "image", "img", "thumbnail", "images", "product", "sku", "cost"].includes(k)
|
|
1750
1750
|
);
|
|
1751
1751
|
const hasProductIdentity = keys.some((k) => ["brand", "model"].includes(k)) && keys.some((k) => ["name", "title", "product_name", "product"].includes(k));
|
|
1752
|
-
const hasPricePattern = /\$\s*\d+/.test(s.content);
|
|
1752
|
+
const hasPricePattern = /\$\s*\d+/.test((_b = s == null ? void 0 : s.content) != null ? _b : "");
|
|
1753
1753
|
return hasStrongProductKey || hasProductIdentity || hasPricePattern || m.type === "product";
|
|
1754
1754
|
}).map((s) => {
|
|
1755
|
-
var _a, _b, _c;
|
|
1755
|
+
var _a, _b, _c, _d;
|
|
1756
1756
|
const m = (_a = s.metadata) != null ? _a : {};
|
|
1757
1757
|
const name = resolveMetadataValue(m, "name");
|
|
1758
1758
|
const brand = resolveMetadataValue(m, "brand");
|
|
1759
1759
|
const price = resolveMetadataValue(m, "price");
|
|
1760
1760
|
const description = resolveMetadataValue(m, "description");
|
|
1761
1761
|
return {
|
|
1762
|
-
id: s.id,
|
|
1763
|
-
name: (
|
|
1762
|
+
id: (_b = s == null ? void 0 : s.id) != null ? _b : `prod_${Math.random().toString(36).substring(2, 8)}`,
|
|
1763
|
+
name: (_d = name != null ? name : ((_c = s == null ? void 0 : s.content) != null ? _c : "").split("\n")[0]) != null ? _d : "Unknown Product",
|
|
1764
1764
|
brand,
|
|
1765
1765
|
price,
|
|
1766
1766
|
image: resolveImage(m),
|
|
1767
1767
|
link: resolveMetadataValue(m, "link"),
|
|
1768
1768
|
description: description ? description : ""
|
|
1769
|
-
//description ?? s.content,
|
|
1770
1769
|
};
|
|
1771
1770
|
});
|
|
1772
1771
|
}
|
|
@@ -3144,10 +3143,10 @@ function ChatWindow({
|
|
|
3144
3143
|
] })
|
|
3145
3144
|
] }),
|
|
3146
3145
|
/* @__PURE__ */ jsxs12("div", { className: "flex items-center gap-1.5", children: [
|
|
3147
|
-
/* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400
|
|
3146
|
+
/* @__PURE__ */ jsx13("div", { className: "flex items-center gap-1.5 mr-2", children: /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-1 text-[10px] text-emerald-500 dark:text-emerald-400", children: [
|
|
3148
3147
|
/* @__PURE__ */ jsx13("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 dark:bg-emerald-400 animate-pulse" }),
|
|
3149
3148
|
"Online"
|
|
3150
|
-
] }),
|
|
3149
|
+
] }) }),
|
|
3151
3150
|
/* @__PURE__ */ jsxs12("div", { className: "flex items-center bg-slate-100/50 dark:bg-white/5 rounded-lg p-0.5 border border-slate-200/50 dark:border-white/5", children: [
|
|
3152
3151
|
mounted && messages.length > 0 && /* @__PURE__ */ jsx13(
|
|
3153
3152
|
"button",
|
|
@@ -3675,8 +3674,8 @@ var IntentClassifier = class {
|
|
|
3675
3674
|
}
|
|
3676
3675
|
// ─── Intent Heuristic Checkers ─────────────────────────────────────────────
|
|
3677
3676
|
static isInformationLookup(query) {
|
|
3678
|
-
if (/^(what|who|explain|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of)\s+/i.test(query)) {
|
|
3679
|
-
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top selling|best)\b/i.test(query)) {
|
|
3677
|
+
if (/^(what|who|explain|explore|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(query)) {
|
|
3678
|
+
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top 10|top selling|best|chart|graph|plot|breakdown|analytics)\b/i.test(query)) {
|
|
3680
3679
|
return true;
|
|
3681
3680
|
}
|
|
3682
3681
|
}
|
|
@@ -3713,7 +3712,7 @@ var Rule1SpecificInfoRule = class {
|
|
|
3713
3712
|
}
|
|
3714
3713
|
evaluate(context, intent) {
|
|
3715
3714
|
const q = (context.userQuery || "").toLowerCase().trim();
|
|
3716
|
-
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|define|where|when|why|meaning of)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
3715
|
+
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|explore|define|where|when|why|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
3717
3716
|
const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
|
|
3718
3717
|
if (isFactQuery && isNonVisual) {
|
|
3719
3718
|
return {
|
|
@@ -4851,6 +4850,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
4851
4850
|
}
|
|
4852
4851
|
static chooseAutomaticVisualization(data, profile, query) {
|
|
4853
4852
|
if (profile.records.length === 0) return null;
|
|
4853
|
+
const q = query.toLowerCase().trim();
|
|
4854
|
+
const isExplicitVisualOrAnalytic = /\b(chart|graph|plot|visualize|trend|monthly|revenue|top\s*\d+|breakdown|analytics|compare|versus|vs\.?|histogram|pie|bar|line|distribution|percentage|share|summary of metrics)\b/i.test(q);
|
|
4855
|
+
if (!isExplicitVisualOrAnalytic) {
|
|
4856
|
+
return null;
|
|
4857
|
+
}
|
|
4854
4858
|
if (profile.dateFields.length > 0 && profile.numericFields.length > 0) {
|
|
4855
4859
|
return this.transformToLineChart(profile);
|
|
4856
4860
|
}
|
|
@@ -4966,6 +4970,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
4966
4970
|
return Array.from(categories);
|
|
4967
4971
|
}
|
|
4968
4972
|
static getProductCategory(item) {
|
|
4973
|
+
if (!item) return null;
|
|
4969
4974
|
const meta = item.metadata || {};
|
|
4970
4975
|
const metadataCategory = resolveMetadataValue(meta, "category");
|
|
4971
4976
|
if (this.isUsableCategory(metadataCategory)) return String(metadataCategory).trim();
|
|
@@ -5082,6 +5087,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5082
5087
|
if (!fields.has(normalized)) fields.set(normalized, clean);
|
|
5083
5088
|
};
|
|
5084
5089
|
data.forEach((item) => {
|
|
5090
|
+
if (!item) return;
|
|
5085
5091
|
Object.keys(item.metadata || {}).forEach(addField);
|
|
5086
5092
|
for (const match of (item.content || "").matchAll(/(?:^|\n)\s*([A-Za-z][A-Za-z0-9_ /-]{1,50})\s*[:\-–]\s*([^\n]+)/g)) {
|
|
5087
5093
|
addField(match[1]);
|
|
@@ -5198,6 +5204,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
5198
5204
|
return true;
|
|
5199
5205
|
}
|
|
5200
5206
|
static extractStockQuantity(item) {
|
|
5207
|
+
if (!item) return null;
|
|
5201
5208
|
const meta = item.metadata || {};
|
|
5202
5209
|
const stockValue = resolveMetadataValue(meta, "stock");
|
|
5203
5210
|
const numericStock = this.toFiniteNumber(stockValue);
|
package/dist/server.js
CHANGED
|
@@ -594,6 +594,7 @@ function cleanApiKeyOverride(apiKeyOverride) {
|
|
|
594
594
|
async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
595
595
|
const effectiveKey = cleanApiKeyOverride(apiKeyOverride);
|
|
596
596
|
const provider = resolveProvider(req.model);
|
|
597
|
+
console.log(`[LLM Gateway Router] Dispatching chat request: model=${req.model}, provider=${provider}, hasGroqKey=${Boolean(process.env.GROQ_API_KEY)}, hasGeminiKey=${Boolean(process.env.GROQ_API_KEY || process.env.GEMINI_API_KEY)}, hasHFToken=${Boolean(process.env.HF_TOKEN)}`);
|
|
597
598
|
try {
|
|
598
599
|
switch (provider) {
|
|
599
600
|
case "groq":
|
|
@@ -612,6 +613,10 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
612
613
|
throw new Error(`Unsupported LLM provider for model: ${req.model}`);
|
|
613
614
|
}
|
|
614
615
|
} catch (error) {
|
|
616
|
+
console.error(`[LLM Gateway Router] Provider '${provider}' failed for model '${req.model}':`, {
|
|
617
|
+
message: error.message,
|
|
618
|
+
stack: error.stack
|
|
619
|
+
});
|
|
615
620
|
if (/rate[- ]?limit|429|exhausted/i.test(error.message)) {
|
|
616
621
|
const isGroqKey = process.env.GROQ_API_KEY || effectiveKey && effectiveKey.startsWith("gsk_");
|
|
617
622
|
const reqModelLower = req.model.toLowerCase();
|
|
@@ -619,7 +624,8 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
619
624
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to secondary Groq model (llama-3.3-70b-versatile)...`);
|
|
620
625
|
try {
|
|
621
626
|
return await handleGroqRequest(__spreadProps(__spreadValues({}, req), { model: "llama-3.3-70b-versatile" }), effectiveKey);
|
|
622
|
-
} catch (
|
|
627
|
+
} catch (fErr) {
|
|
628
|
+
console.error("[LLM Gateway] Fallback groq/llama-3.3-70b-versatile failed:", fErr.message);
|
|
623
629
|
}
|
|
624
630
|
}
|
|
625
631
|
const geminiKey = process.env.GEMINI_API_KEY || effectiveKey;
|
|
@@ -627,14 +633,16 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
627
633
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Google Gemini (gemini-2.5-flash)...`);
|
|
628
634
|
try {
|
|
629
635
|
return await handleGeminiRequest(__spreadProps(__spreadValues({}, req), { model: "gemini-2.5-flash" }), effectiveKey);
|
|
630
|
-
} catch (
|
|
636
|
+
} catch (fErr) {
|
|
637
|
+
console.error("[LLM Gateway] Fallback gemini-2.5-flash failed:", fErr.message);
|
|
631
638
|
}
|
|
632
639
|
}
|
|
633
640
|
if (provider !== "huggingface" && (process.env.HF_TOKEN || process.env.HUGGINGFACE_API_KEY)) {
|
|
634
641
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Hugging Face (Qwen/Qwen2.5-Coder-32B-Instruct)...`);
|
|
635
642
|
try {
|
|
636
643
|
return await handleHuggingFaceChatRequest(__spreadProps(__spreadValues({}, req), { model: "Qwen/Qwen2.5-Coder-32B-Instruct" }), effectiveKey);
|
|
637
|
-
} catch (
|
|
644
|
+
} catch (fErr) {
|
|
645
|
+
console.error("[LLM Gateway] Fallback HuggingFace Qwen failed:", fErr.message);
|
|
638
646
|
}
|
|
639
647
|
}
|
|
640
648
|
if (provider !== "openai" && process.env.OPENAI_API_KEY) {
|
|
@@ -3489,12 +3497,13 @@ var OpenAIProvider = class {
|
|
|
3489
3497
|
role: "system",
|
|
3490
3498
|
content: buildSystemContent(basePrompt, context)
|
|
3491
3499
|
};
|
|
3500
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3501
|
+
role: m.role || "user",
|
|
3502
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3503
|
+
}));
|
|
3492
3504
|
const formattedMessages = [
|
|
3493
3505
|
systemMessage,
|
|
3494
|
-
...
|
|
3495
|
-
role: m.role,
|
|
3496
|
-
content: m.content
|
|
3497
|
-
}))
|
|
3506
|
+
...safeMessages
|
|
3498
3507
|
];
|
|
3499
3508
|
const completion = await this.client.chat.completions.create({
|
|
3500
3509
|
model: this.llmConfig.model,
|
|
@@ -3513,12 +3522,13 @@ var OpenAIProvider = class {
|
|
|
3513
3522
|
role: "system",
|
|
3514
3523
|
content: buildSystemContent(basePrompt, context)
|
|
3515
3524
|
};
|
|
3525
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3526
|
+
role: m.role || "user",
|
|
3527
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3528
|
+
}));
|
|
3516
3529
|
const formattedMessages = [
|
|
3517
3530
|
systemMessage,
|
|
3518
|
-
...
|
|
3519
|
-
role: m.role,
|
|
3520
|
-
content: m.content
|
|
3521
|
-
}))
|
|
3531
|
+
...safeStreamMessages
|
|
3522
3532
|
];
|
|
3523
3533
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
3524
3534
|
model: this.llmConfig.model,
|
|
@@ -4049,9 +4059,9 @@ var GeminiProvider = class {
|
|
|
4049
4059
|
* - Messages must strictly alternate between `user` and `model`.
|
|
4050
4060
|
*/
|
|
4051
4061
|
buildGeminiContents(messages) {
|
|
4052
|
-
return messages.filter((m) => m.role !== "system").map((m) => ({
|
|
4062
|
+
return (messages || []).filter((m) => Boolean(m && typeof m === "object" && m.role !== "system")).map((m) => ({
|
|
4053
4063
|
role: m.role === "assistant" ? "model" : "user",
|
|
4054
|
-
parts: [{ text: m.content }]
|
|
4064
|
+
parts: [{ text: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : "" }]
|
|
4055
4065
|
}));
|
|
4056
4066
|
}
|
|
4057
4067
|
// -------------------------------------------------------------------------
|
|
@@ -4254,12 +4264,13 @@ var GroqProvider = class {
|
|
|
4254
4264
|
role: "system",
|
|
4255
4265
|
content: buildSystemContent(basePrompt, context)
|
|
4256
4266
|
};
|
|
4267
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4268
|
+
role: m.role || "user",
|
|
4269
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4270
|
+
}));
|
|
4257
4271
|
const formattedMessages = [
|
|
4258
4272
|
systemMessage,
|
|
4259
|
-
...
|
|
4260
|
-
role: m.role,
|
|
4261
|
-
content: m.content
|
|
4262
|
-
}))
|
|
4273
|
+
...safeMessages
|
|
4263
4274
|
];
|
|
4264
4275
|
const completion = await this.client.chat.completions.create({
|
|
4265
4276
|
model: this.llmConfig.model,
|
|
@@ -4278,12 +4289,13 @@ var GroqProvider = class {
|
|
|
4278
4289
|
role: "system",
|
|
4279
4290
|
content: buildSystemContent(basePrompt, context)
|
|
4280
4291
|
};
|
|
4292
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4293
|
+
role: m.role || "user",
|
|
4294
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4295
|
+
}));
|
|
4281
4296
|
const formattedMessages = [
|
|
4282
4297
|
systemMessage,
|
|
4283
|
-
...
|
|
4284
|
-
role: m.role,
|
|
4285
|
-
content: m.content
|
|
4286
|
-
}))
|
|
4298
|
+
...safeStreamMessages
|
|
4287
4299
|
];
|
|
4288
4300
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4289
4301
|
model: this.llmConfig.model,
|
|
@@ -4412,12 +4424,13 @@ var QwenProvider = class {
|
|
|
4412
4424
|
role: "system",
|
|
4413
4425
|
content: buildSystemContent(basePrompt, context)
|
|
4414
4426
|
};
|
|
4427
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4428
|
+
role: m.role || "user",
|
|
4429
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4430
|
+
}));
|
|
4415
4431
|
const formattedMessages = [
|
|
4416
4432
|
systemMessage,
|
|
4417
|
-
...
|
|
4418
|
-
role: m.role,
|
|
4419
|
-
content: m.content
|
|
4420
|
-
}))
|
|
4433
|
+
...safeMessages
|
|
4421
4434
|
];
|
|
4422
4435
|
const completion = await this.client.chat.completions.create({
|
|
4423
4436
|
model: this.llmConfig.model,
|
|
@@ -4436,12 +4449,13 @@ var QwenProvider = class {
|
|
|
4436
4449
|
role: "system",
|
|
4437
4450
|
content: buildSystemContent(basePrompt, context)
|
|
4438
4451
|
};
|
|
4452
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4453
|
+
role: m.role || "user",
|
|
4454
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4455
|
+
}));
|
|
4439
4456
|
const formattedMessages = [
|
|
4440
4457
|
systemMessage,
|
|
4441
|
-
...
|
|
4442
|
-
role: m.role,
|
|
4443
|
-
content: m.content
|
|
4444
|
-
}))
|
|
4458
|
+
...safeStreamMessages
|
|
4445
4459
|
];
|
|
4446
4460
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4447
4461
|
model: this.llmConfig.model,
|
|
@@ -4623,12 +4637,16 @@ var UniversalLLMAdapter = class {
|
|
|
4623
4637
|
async chat(messages, context) {
|
|
4624
4638
|
var _a2, _b, _c;
|
|
4625
4639
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4640
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4641
|
+
role: m.role || "user",
|
|
4642
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4643
|
+
}));
|
|
4626
4644
|
const formattedMessages = [
|
|
4627
4645
|
{ role: "system", content: `${this.systemPrompt}
|
|
4628
4646
|
|
|
4629
4647
|
Context:
|
|
4630
4648
|
${context != null ? context : "None"}` },
|
|
4631
|
-
...
|
|
4649
|
+
...safeMessages
|
|
4632
4650
|
];
|
|
4633
4651
|
let payload;
|
|
4634
4652
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -4700,12 +4718,16 @@ ${context != null ? context : "None"}` },
|
|
|
4700
4718
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4701
4719
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
4702
4720
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
4721
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4722
|
+
role: m.role || "user",
|
|
4723
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4724
|
+
}));
|
|
4703
4725
|
const formattedMessages = [
|
|
4704
4726
|
{ role: "system", content: `${this.systemPrompt}
|
|
4705
4727
|
|
|
4706
4728
|
Context:
|
|
4707
4729
|
${context != null ? context : "None"}` },
|
|
4708
|
-
...
|
|
4730
|
+
...safeMessages
|
|
4709
4731
|
];
|
|
4710
4732
|
let payload;
|
|
4711
4733
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -6849,8 +6871,8 @@ var IntentClassifier = class {
|
|
|
6849
6871
|
}
|
|
6850
6872
|
// ─── Intent Heuristic Checkers ─────────────────────────────────────────────
|
|
6851
6873
|
static isInformationLookup(query) {
|
|
6852
|
-
if (/^(what|who|explain|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of)\s+/i.test(query)) {
|
|
6853
|
-
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top selling|best)\b/i.test(query)) {
|
|
6874
|
+
if (/^(what|who|explain|explore|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(query)) {
|
|
6875
|
+
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top 10|top selling|best|chart|graph|plot|breakdown|analytics)\b/i.test(query)) {
|
|
6854
6876
|
return true;
|
|
6855
6877
|
}
|
|
6856
6878
|
}
|
|
@@ -6887,7 +6909,7 @@ var Rule1SpecificInfoRule = class {
|
|
|
6887
6909
|
}
|
|
6888
6910
|
evaluate(context, intent) {
|
|
6889
6911
|
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6890
|
-
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|define|where|when|why|meaning of)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
6912
|
+
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|explore|define|where|when|why|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
6891
6913
|
const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
|
|
6892
6914
|
if (isFactQuery && isNonVisual) {
|
|
6893
6915
|
return {
|
|
@@ -8174,6 +8196,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
8174
8196
|
}
|
|
8175
8197
|
static chooseAutomaticVisualization(data, profile, query) {
|
|
8176
8198
|
if (profile.records.length === 0) return null;
|
|
8199
|
+
const q = query.toLowerCase().trim();
|
|
8200
|
+
const isExplicitVisualOrAnalytic = /\b(chart|graph|plot|visualize|trend|monthly|revenue|top\s*\d+|breakdown|analytics|compare|versus|vs\.?|histogram|pie|bar|line|distribution|percentage|share|summary of metrics)\b/i.test(q);
|
|
8201
|
+
if (!isExplicitVisualOrAnalytic) {
|
|
8202
|
+
return null;
|
|
8203
|
+
}
|
|
8177
8204
|
if (profile.dateFields.length > 0 && profile.numericFields.length > 0) {
|
|
8178
8205
|
return this.transformToLineChart(profile);
|
|
8179
8206
|
}
|
|
@@ -8289,6 +8316,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8289
8316
|
return Array.from(categories);
|
|
8290
8317
|
}
|
|
8291
8318
|
static getProductCategory(item) {
|
|
8319
|
+
if (!item) return null;
|
|
8292
8320
|
const meta = item.metadata || {};
|
|
8293
8321
|
const metadataCategory = resolveMetadataValue(meta, "category");
|
|
8294
8322
|
if (this.isUsableCategory(metadataCategory)) return String(metadataCategory).trim();
|
|
@@ -8405,6 +8433,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8405
8433
|
if (!fields.has(normalized)) fields.set(normalized, clean);
|
|
8406
8434
|
};
|
|
8407
8435
|
data.forEach((item) => {
|
|
8436
|
+
if (!item) return;
|
|
8408
8437
|
Object.keys(item.metadata || {}).forEach(addField);
|
|
8409
8438
|
for (const match of (item.content || "").matchAll(/(?:^|\n)\s*([A-Za-z][A-Za-z0-9_ /-]{1,50})\s*[:\-–]\s*([^\n]+)/g)) {
|
|
8410
8439
|
addField(match[1]);
|
|
@@ -8521,6 +8550,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8521
8550
|
return true;
|
|
8522
8551
|
}
|
|
8523
8552
|
static extractStockQuantity(item) {
|
|
8553
|
+
if (!item) return null;
|
|
8524
8554
|
const meta = item.metadata || {};
|
|
8525
8555
|
const stockValue = resolveMetadataValue(meta, "stock");
|
|
8526
8556
|
const numericStock = this.toFiniteNumber(stockValue);
|
|
@@ -9781,7 +9811,10 @@ ${context}`;
|
|
|
9781
9811
|
Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.
|
|
9782
9812
|
|
|
9783
9813
|
History:
|
|
9784
|
-
${history.map((m) =>
|
|
9814
|
+
${(history || []).map((m) => {
|
|
9815
|
+
var _a2;
|
|
9816
|
+
return `${(m == null ? void 0 : m.role) || "user"}: ${(_a2 = m == null ? void 0 : m.content) != null ? _a2 : ""}`;
|
|
9817
|
+
}).join("\n")}
|
|
9785
9818
|
|
|
9786
9819
|
New Question: ${question}
|
|
9787
9820
|
|
|
@@ -9805,8 +9838,11 @@ Optimized Search Query:`;
|
|
|
9805
9838
|
const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
|
|
9806
9839
|
try {
|
|
9807
9840
|
const { sources } = await this.retrieve(query, { namespace: ns, topK: 5 });
|
|
9808
|
-
if (sources.length === 0) return [];
|
|
9809
|
-
const context = sources.map((s) =>
|
|
9841
|
+
if (!sources || sources.length === 0) return [];
|
|
9842
|
+
const context = sources.map((s) => {
|
|
9843
|
+
var _a2;
|
|
9844
|
+
return (_a2 = s == null ? void 0 : s.content) != null ? _a2 : "";
|
|
9845
|
+
}).join("\n\n---\n\n");
|
|
9810
9846
|
const prompt = `Based on the following snippets from a document, what are at least 5 short, relevant questions a user might ask?
|
|
9811
9847
|
Focus on questions that can be answered by the context.
|
|
9812
9848
|
Keep each question under 10 words and make them very specific to the content.
|
package/dist/server.mjs
CHANGED
|
@@ -579,6 +579,7 @@ function cleanApiKeyOverride(apiKeyOverride) {
|
|
|
579
579
|
async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
580
580
|
const effectiveKey = cleanApiKeyOverride(apiKeyOverride);
|
|
581
581
|
const provider = resolveProvider(req.model);
|
|
582
|
+
console.log(`[LLM Gateway Router] Dispatching chat request: model=${req.model}, provider=${provider}, hasGroqKey=${Boolean(process.env.GROQ_API_KEY)}, hasGeminiKey=${Boolean(process.env.GROQ_API_KEY || process.env.GEMINI_API_KEY)}, hasHFToken=${Boolean(process.env.HF_TOKEN)}`);
|
|
582
583
|
try {
|
|
583
584
|
switch (provider) {
|
|
584
585
|
case "groq":
|
|
@@ -597,6 +598,10 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
597
598
|
throw new Error(`Unsupported LLM provider for model: ${req.model}`);
|
|
598
599
|
}
|
|
599
600
|
} catch (error) {
|
|
601
|
+
console.error(`[LLM Gateway Router] Provider '${provider}' failed for model '${req.model}':`, {
|
|
602
|
+
message: error.message,
|
|
603
|
+
stack: error.stack
|
|
604
|
+
});
|
|
600
605
|
if (/rate[- ]?limit|429|exhausted/i.test(error.message)) {
|
|
601
606
|
const isGroqKey = process.env.GROQ_API_KEY || effectiveKey && effectiveKey.startsWith("gsk_");
|
|
602
607
|
const reqModelLower = req.model.toLowerCase();
|
|
@@ -604,7 +609,8 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
604
609
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to secondary Groq model (llama-3.3-70b-versatile)...`);
|
|
605
610
|
try {
|
|
606
611
|
return await handleGroqRequest(__spreadProps(__spreadValues({}, req), { model: "llama-3.3-70b-versatile" }), effectiveKey);
|
|
607
|
-
} catch (
|
|
612
|
+
} catch (fErr) {
|
|
613
|
+
console.error("[LLM Gateway] Fallback groq/llama-3.3-70b-versatile failed:", fErr.message);
|
|
608
614
|
}
|
|
609
615
|
}
|
|
610
616
|
const geminiKey = process.env.GEMINI_API_KEY || effectiveKey;
|
|
@@ -612,14 +618,16 @@ async function dispatchChatCompletion(req, apiKeyOverride) {
|
|
|
612
618
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Google Gemini (gemini-2.5-flash)...`);
|
|
613
619
|
try {
|
|
614
620
|
return await handleGeminiRequest(__spreadProps(__spreadValues({}, req), { model: "gemini-2.5-flash" }), effectiveKey);
|
|
615
|
-
} catch (
|
|
621
|
+
} catch (fErr) {
|
|
622
|
+
console.error("[LLM Gateway] Fallback gemini-2.5-flash failed:", fErr.message);
|
|
616
623
|
}
|
|
617
624
|
}
|
|
618
625
|
if (provider !== "huggingface" && (process.env.HF_TOKEN || process.env.HUGGINGFACE_API_KEY)) {
|
|
619
626
|
console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Hugging Face (Qwen/Qwen2.5-Coder-32B-Instruct)...`);
|
|
620
627
|
try {
|
|
621
628
|
return await handleHuggingFaceChatRequest(__spreadProps(__spreadValues({}, req), { model: "Qwen/Qwen2.5-Coder-32B-Instruct" }), effectiveKey);
|
|
622
|
-
} catch (
|
|
629
|
+
} catch (fErr) {
|
|
630
|
+
console.error("[LLM Gateway] Fallback HuggingFace Qwen failed:", fErr.message);
|
|
623
631
|
}
|
|
624
632
|
}
|
|
625
633
|
if (provider !== "openai" && process.env.OPENAI_API_KEY) {
|
|
@@ -3393,12 +3401,13 @@ var OpenAIProvider = class {
|
|
|
3393
3401
|
role: "system",
|
|
3394
3402
|
content: buildSystemContent(basePrompt, context)
|
|
3395
3403
|
};
|
|
3404
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3405
|
+
role: m.role || "user",
|
|
3406
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3407
|
+
}));
|
|
3396
3408
|
const formattedMessages = [
|
|
3397
3409
|
systemMessage,
|
|
3398
|
-
...
|
|
3399
|
-
role: m.role,
|
|
3400
|
-
content: m.content
|
|
3401
|
-
}))
|
|
3410
|
+
...safeMessages
|
|
3402
3411
|
];
|
|
3403
3412
|
const completion = await this.client.chat.completions.create({
|
|
3404
3413
|
model: this.llmConfig.model,
|
|
@@ -3417,12 +3426,13 @@ var OpenAIProvider = class {
|
|
|
3417
3426
|
role: "system",
|
|
3418
3427
|
content: buildSystemContent(basePrompt, context)
|
|
3419
3428
|
};
|
|
3429
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3430
|
+
role: m.role || "user",
|
|
3431
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3432
|
+
}));
|
|
3420
3433
|
const formattedMessages = [
|
|
3421
3434
|
systemMessage,
|
|
3422
|
-
...
|
|
3423
|
-
role: m.role,
|
|
3424
|
-
content: m.content
|
|
3425
|
-
}))
|
|
3435
|
+
...safeStreamMessages
|
|
3426
3436
|
];
|
|
3427
3437
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
3428
3438
|
model: this.llmConfig.model,
|
|
@@ -3953,9 +3963,9 @@ var GeminiProvider = class {
|
|
|
3953
3963
|
* - Messages must strictly alternate between `user` and `model`.
|
|
3954
3964
|
*/
|
|
3955
3965
|
buildGeminiContents(messages) {
|
|
3956
|
-
return messages.filter((m) => m.role !== "system").map((m) => ({
|
|
3966
|
+
return (messages || []).filter((m) => Boolean(m && typeof m === "object" && m.role !== "system")).map((m) => ({
|
|
3957
3967
|
role: m.role === "assistant" ? "model" : "user",
|
|
3958
|
-
parts: [{ text: m.content }]
|
|
3968
|
+
parts: [{ text: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : "" }]
|
|
3959
3969
|
}));
|
|
3960
3970
|
}
|
|
3961
3971
|
// -------------------------------------------------------------------------
|
|
@@ -4158,12 +4168,13 @@ var GroqProvider = class {
|
|
|
4158
4168
|
role: "system",
|
|
4159
4169
|
content: buildSystemContent(basePrompt, context)
|
|
4160
4170
|
};
|
|
4171
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4172
|
+
role: m.role || "user",
|
|
4173
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4174
|
+
}));
|
|
4161
4175
|
const formattedMessages = [
|
|
4162
4176
|
systemMessage,
|
|
4163
|
-
...
|
|
4164
|
-
role: m.role,
|
|
4165
|
-
content: m.content
|
|
4166
|
-
}))
|
|
4177
|
+
...safeMessages
|
|
4167
4178
|
];
|
|
4168
4179
|
const completion = await this.client.chat.completions.create({
|
|
4169
4180
|
model: this.llmConfig.model,
|
|
@@ -4182,12 +4193,13 @@ var GroqProvider = class {
|
|
|
4182
4193
|
role: "system",
|
|
4183
4194
|
content: buildSystemContent(basePrompt, context)
|
|
4184
4195
|
};
|
|
4196
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4197
|
+
role: m.role || "user",
|
|
4198
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4199
|
+
}));
|
|
4185
4200
|
const formattedMessages = [
|
|
4186
4201
|
systemMessage,
|
|
4187
|
-
...
|
|
4188
|
-
role: m.role,
|
|
4189
|
-
content: m.content
|
|
4190
|
-
}))
|
|
4202
|
+
...safeStreamMessages
|
|
4191
4203
|
];
|
|
4192
4204
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4193
4205
|
model: this.llmConfig.model,
|
|
@@ -4316,12 +4328,13 @@ var QwenProvider = class {
|
|
|
4316
4328
|
role: "system",
|
|
4317
4329
|
content: buildSystemContent(basePrompt, context)
|
|
4318
4330
|
};
|
|
4331
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4332
|
+
role: m.role || "user",
|
|
4333
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4334
|
+
}));
|
|
4319
4335
|
const formattedMessages = [
|
|
4320
4336
|
systemMessage,
|
|
4321
|
-
...
|
|
4322
|
-
role: m.role,
|
|
4323
|
-
content: m.content
|
|
4324
|
-
}))
|
|
4337
|
+
...safeMessages
|
|
4325
4338
|
];
|
|
4326
4339
|
const completion = await this.client.chat.completions.create({
|
|
4327
4340
|
model: this.llmConfig.model,
|
|
@@ -4340,12 +4353,13 @@ var QwenProvider = class {
|
|
|
4340
4353
|
role: "system",
|
|
4341
4354
|
content: buildSystemContent(basePrompt, context)
|
|
4342
4355
|
};
|
|
4356
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4357
|
+
role: m.role || "user",
|
|
4358
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4359
|
+
}));
|
|
4343
4360
|
const formattedMessages = [
|
|
4344
4361
|
systemMessage,
|
|
4345
|
-
...
|
|
4346
|
-
role: m.role,
|
|
4347
|
-
content: m.content
|
|
4348
|
-
}))
|
|
4362
|
+
...safeStreamMessages
|
|
4349
4363
|
];
|
|
4350
4364
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4351
4365
|
model: this.llmConfig.model,
|
|
@@ -4527,12 +4541,16 @@ var UniversalLLMAdapter = class {
|
|
|
4527
4541
|
async chat(messages, context) {
|
|
4528
4542
|
var _a2, _b, _c;
|
|
4529
4543
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4544
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4545
|
+
role: m.role || "user",
|
|
4546
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4547
|
+
}));
|
|
4530
4548
|
const formattedMessages = [
|
|
4531
4549
|
{ role: "system", content: `${this.systemPrompt}
|
|
4532
4550
|
|
|
4533
4551
|
Context:
|
|
4534
4552
|
${context != null ? context : "None"}` },
|
|
4535
|
-
...
|
|
4553
|
+
...safeMessages
|
|
4536
4554
|
];
|
|
4537
4555
|
let payload;
|
|
4538
4556
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -4604,12 +4622,16 @@ ${context != null ? context : "None"}` },
|
|
|
4604
4622
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4605
4623
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
4606
4624
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
4625
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4626
|
+
role: m.role || "user",
|
|
4627
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4628
|
+
}));
|
|
4607
4629
|
const formattedMessages = [
|
|
4608
4630
|
{ role: "system", content: `${this.systemPrompt}
|
|
4609
4631
|
|
|
4610
4632
|
Context:
|
|
4611
4633
|
${context != null ? context : "None"}` },
|
|
4612
|
-
...
|
|
4634
|
+
...safeMessages
|
|
4613
4635
|
];
|
|
4614
4636
|
let payload;
|
|
4615
4637
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -6753,8 +6775,8 @@ var IntentClassifier = class {
|
|
|
6753
6775
|
}
|
|
6754
6776
|
// ─── Intent Heuristic Checkers ─────────────────────────────────────────────
|
|
6755
6777
|
static isInformationLookup(query) {
|
|
6756
|
-
if (/^(what|who|explain|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of)\s+/i.test(query)) {
|
|
6757
|
-
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top selling|best)\b/i.test(query)) {
|
|
6778
|
+
if (/^(what|who|explain|explore|define|where|when|why|how|how does|can|could|does|do|is|are|has|have|will|should|would|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(query)) {
|
|
6779
|
+
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top 10|top selling|best|chart|graph|plot|breakdown|analytics)\b/i.test(query)) {
|
|
6758
6780
|
return true;
|
|
6759
6781
|
}
|
|
6760
6782
|
}
|
|
@@ -6791,7 +6813,7 @@ var Rule1SpecificInfoRule = class {
|
|
|
6791
6813
|
}
|
|
6792
6814
|
evaluate(context, intent) {
|
|
6793
6815
|
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6794
|
-
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|define|where|when|why|meaning of)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
6816
|
+
const isFactQuery = intent === "information_lookup" || /^(what|who|explain|explore|define|where|when|why|meaning of|tell me about|show details of|overview of|summarize)\s+/i.test(q) || /^(what is the price of|price of|cost of)\b/i.test(q);
|
|
6795
6817
|
const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
|
|
6796
6818
|
if (isFactQuery && isNonVisual) {
|
|
6797
6819
|
return {
|
|
@@ -8078,6 +8100,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
8078
8100
|
}
|
|
8079
8101
|
static chooseAutomaticVisualization(data, profile, query) {
|
|
8080
8102
|
if (profile.records.length === 0) return null;
|
|
8103
|
+
const q = query.toLowerCase().trim();
|
|
8104
|
+
const isExplicitVisualOrAnalytic = /\b(chart|graph|plot|visualize|trend|monthly|revenue|top\s*\d+|breakdown|analytics|compare|versus|vs\.?|histogram|pie|bar|line|distribution|percentage|share|summary of metrics)\b/i.test(q);
|
|
8105
|
+
if (!isExplicitVisualOrAnalytic) {
|
|
8106
|
+
return null;
|
|
8107
|
+
}
|
|
8081
8108
|
if (profile.dateFields.length > 0 && profile.numericFields.length > 0) {
|
|
8082
8109
|
return this.transformToLineChart(profile);
|
|
8083
8110
|
}
|
|
@@ -8193,6 +8220,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8193
8220
|
return Array.from(categories);
|
|
8194
8221
|
}
|
|
8195
8222
|
static getProductCategory(item) {
|
|
8223
|
+
if (!item) return null;
|
|
8196
8224
|
const meta = item.metadata || {};
|
|
8197
8225
|
const metadataCategory = resolveMetadataValue(meta, "category");
|
|
8198
8226
|
if (this.isUsableCategory(metadataCategory)) return String(metadataCategory).trim();
|
|
@@ -8309,6 +8337,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8309
8337
|
if (!fields.has(normalized)) fields.set(normalized, clean);
|
|
8310
8338
|
};
|
|
8311
8339
|
data.forEach((item) => {
|
|
8340
|
+
if (!item) return;
|
|
8312
8341
|
Object.keys(item.metadata || {}).forEach(addField);
|
|
8313
8342
|
for (const match of (item.content || "").matchAll(/(?:^|\n)\s*([A-Za-z][A-Za-z0-9_ /-]{1,50})\s*[:\-–]\s*([^\n]+)/g)) {
|
|
8314
8343
|
addField(match[1]);
|
|
@@ -8425,6 +8454,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8425
8454
|
return true;
|
|
8426
8455
|
}
|
|
8427
8456
|
static extractStockQuantity(item) {
|
|
8457
|
+
if (!item) return null;
|
|
8428
8458
|
const meta = item.metadata || {};
|
|
8429
8459
|
const stockValue = resolveMetadataValue(meta, "stock");
|
|
8430
8460
|
const numericStock = this.toFiniteNumber(stockValue);
|
|
@@ -9685,7 +9715,10 @@ ${context}`;
|
|
|
9685
9715
|
Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.
|
|
9686
9716
|
|
|
9687
9717
|
History:
|
|
9688
|
-
${history.map((m) =>
|
|
9718
|
+
${(history || []).map((m) => {
|
|
9719
|
+
var _a2;
|
|
9720
|
+
return `${(m == null ? void 0 : m.role) || "user"}: ${(_a2 = m == null ? void 0 : m.content) != null ? _a2 : ""}`;
|
|
9721
|
+
}).join("\n")}
|
|
9689
9722
|
|
|
9690
9723
|
New Question: ${question}
|
|
9691
9724
|
|
|
@@ -9709,8 +9742,11 @@ Optimized Search Query:`;
|
|
|
9709
9742
|
const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
|
|
9710
9743
|
try {
|
|
9711
9744
|
const { sources } = await this.retrieve(query, { namespace: ns, topK: 5 });
|
|
9712
|
-
if (sources.length === 0) return [];
|
|
9713
|
-
const context = sources.map((s) =>
|
|
9745
|
+
if (!sources || sources.length === 0) return [];
|
|
9746
|
+
const context = sources.map((s) => {
|
|
9747
|
+
var _a2;
|
|
9748
|
+
return (_a2 = s == null ? void 0 : s.content) != null ? _a2 : "";
|
|
9749
|
+
}).join("\n\n---\n\n");
|
|
9714
9750
|
const prompt = `Based on the following snippets from a document, what are at least 5 short, relevant questions a user might ask?
|
|
9715
9751
|
Focus on questions that can be answered by the context.
|
|
9716
9752
|
Keep each question under 10 words and make them very specific to the content.
|