@retrivora-ai/rag-engine 2.0.8 → 2.1.2
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 +113 -75
- package/dist/handlers/index.mjs +113 -75
- package/dist/index.js +19 -12
- package/dist/index.mjs +19 -12
- package/dist/server.js +113 -75
- package/dist/server.mjs +113 -75
- 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 +56 -36
- 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/handlers/index.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) {
|
|
@@ -3428,12 +3436,13 @@ var OpenAIProvider = class {
|
|
|
3428
3436
|
role: "system",
|
|
3429
3437
|
content: buildSystemContent(basePrompt, context)
|
|
3430
3438
|
};
|
|
3439
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3440
|
+
role: m.role || "user",
|
|
3441
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3442
|
+
}));
|
|
3431
3443
|
const formattedMessages = [
|
|
3432
3444
|
systemMessage,
|
|
3433
|
-
...
|
|
3434
|
-
role: m.role,
|
|
3435
|
-
content: m.content
|
|
3436
|
-
}))
|
|
3445
|
+
...safeMessages
|
|
3437
3446
|
];
|
|
3438
3447
|
const completion = await this.client.chat.completions.create({
|
|
3439
3448
|
model: this.llmConfig.model,
|
|
@@ -3452,12 +3461,13 @@ var OpenAIProvider = class {
|
|
|
3452
3461
|
role: "system",
|
|
3453
3462
|
content: buildSystemContent(basePrompt, context)
|
|
3454
3463
|
};
|
|
3464
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
3465
|
+
role: m.role || "user",
|
|
3466
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
3467
|
+
}));
|
|
3455
3468
|
const formattedMessages = [
|
|
3456
3469
|
systemMessage,
|
|
3457
|
-
...
|
|
3458
|
-
role: m.role,
|
|
3459
|
-
content: m.content
|
|
3460
|
-
}))
|
|
3470
|
+
...safeStreamMessages
|
|
3461
3471
|
];
|
|
3462
3472
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
3463
3473
|
model: this.llmConfig.model,
|
|
@@ -3988,9 +3998,9 @@ var GeminiProvider = class {
|
|
|
3988
3998
|
* - Messages must strictly alternate between `user` and `model`.
|
|
3989
3999
|
*/
|
|
3990
4000
|
buildGeminiContents(messages) {
|
|
3991
|
-
return messages.filter((m) => m.role !== "system").map((m) => ({
|
|
4001
|
+
return (messages || []).filter((m) => Boolean(m && typeof m === "object" && m.role !== "system")).map((m) => ({
|
|
3992
4002
|
role: m.role === "assistant" ? "model" : "user",
|
|
3993
|
-
parts: [{ text: m.content }]
|
|
4003
|
+
parts: [{ text: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : "" }]
|
|
3994
4004
|
}));
|
|
3995
4005
|
}
|
|
3996
4006
|
// -------------------------------------------------------------------------
|
|
@@ -4193,12 +4203,13 @@ var GroqProvider = class {
|
|
|
4193
4203
|
role: "system",
|
|
4194
4204
|
content: buildSystemContent(basePrompt, context)
|
|
4195
4205
|
};
|
|
4206
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4207
|
+
role: m.role || "user",
|
|
4208
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4209
|
+
}));
|
|
4196
4210
|
const formattedMessages = [
|
|
4197
4211
|
systemMessage,
|
|
4198
|
-
...
|
|
4199
|
-
role: m.role,
|
|
4200
|
-
content: m.content
|
|
4201
|
-
}))
|
|
4212
|
+
...safeMessages
|
|
4202
4213
|
];
|
|
4203
4214
|
const completion = await this.client.chat.completions.create({
|
|
4204
4215
|
model: this.llmConfig.model,
|
|
@@ -4217,12 +4228,13 @@ var GroqProvider = class {
|
|
|
4217
4228
|
role: "system",
|
|
4218
4229
|
content: buildSystemContent(basePrompt, context)
|
|
4219
4230
|
};
|
|
4231
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4232
|
+
role: m.role || "user",
|
|
4233
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4234
|
+
}));
|
|
4220
4235
|
const formattedMessages = [
|
|
4221
4236
|
systemMessage,
|
|
4222
|
-
...
|
|
4223
|
-
role: m.role,
|
|
4224
|
-
content: m.content
|
|
4225
|
-
}))
|
|
4237
|
+
...safeStreamMessages
|
|
4226
4238
|
];
|
|
4227
4239
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4228
4240
|
model: this.llmConfig.model,
|
|
@@ -4351,12 +4363,13 @@ var QwenProvider = class {
|
|
|
4351
4363
|
role: "system",
|
|
4352
4364
|
content: buildSystemContent(basePrompt, context)
|
|
4353
4365
|
};
|
|
4366
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4367
|
+
role: m.role || "user",
|
|
4368
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4369
|
+
}));
|
|
4354
4370
|
const formattedMessages = [
|
|
4355
4371
|
systemMessage,
|
|
4356
|
-
...
|
|
4357
|
-
role: m.role,
|
|
4358
|
-
content: m.content
|
|
4359
|
-
}))
|
|
4372
|
+
...safeMessages
|
|
4360
4373
|
];
|
|
4361
4374
|
const completion = await this.client.chat.completions.create({
|
|
4362
4375
|
model: this.llmConfig.model,
|
|
@@ -4375,12 +4388,13 @@ var QwenProvider = class {
|
|
|
4375
4388
|
role: "system",
|
|
4376
4389
|
content: buildSystemContent(basePrompt, context)
|
|
4377
4390
|
};
|
|
4391
|
+
const safeStreamMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4392
|
+
role: m.role || "user",
|
|
4393
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4394
|
+
}));
|
|
4378
4395
|
const formattedMessages = [
|
|
4379
4396
|
systemMessage,
|
|
4380
|
-
...
|
|
4381
|
-
role: m.role,
|
|
4382
|
-
content: m.content
|
|
4383
|
-
}))
|
|
4397
|
+
...safeStreamMessages
|
|
4384
4398
|
];
|
|
4385
4399
|
const stream = yield new __await(this.client.chat.completions.create({
|
|
4386
4400
|
model: this.llmConfig.model,
|
|
@@ -4521,14 +4535,18 @@ var UniversalLLMAdapter = class {
|
|
|
4521
4535
|
});
|
|
4522
4536
|
}
|
|
4523
4537
|
async chat(messages, context) {
|
|
4524
|
-
var _a2, _b, _c;
|
|
4538
|
+
var _a2, _b, _c, _d, _e;
|
|
4525
4539
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4540
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4541
|
+
role: m.role || "user",
|
|
4542
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4543
|
+
}));
|
|
4526
4544
|
const formattedMessages = [
|
|
4527
4545
|
{ role: "system", content: `${this.systemPrompt}
|
|
4528
4546
|
|
|
4529
4547
|
Context:
|
|
4530
4548
|
${context != null ? context : "None"}` },
|
|
4531
|
-
...
|
|
4549
|
+
...safeMessages
|
|
4532
4550
|
];
|
|
4533
4551
|
let payload;
|
|
4534
4552
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -4546,8 +4564,15 @@ ${context != null ? context : "None"}` },
|
|
|
4546
4564
|
temperature: this.temperature
|
|
4547
4565
|
};
|
|
4548
4566
|
}
|
|
4549
|
-
|
|
4550
|
-
|
|
4567
|
+
try {
|
|
4568
|
+
const { data: data2 } = await this.http.post(path2, payload);
|
|
4569
|
+
const extractPath2 = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
|
|
4570
|
+
const result2 = (_c = resolvePath(data2, extractPath2)) != null ? _c : extractContent(data2);
|
|
4571
|
+
if (result2 !== void 0) {
|
|
4572
|
+
return String(result2);
|
|
4573
|
+
}
|
|
4574
|
+
} catch (httpErr) {
|
|
4575
|
+
console.warn(`[UniversalLLMAdapter] Direct HTTP POST to ${this.baseUrl}${path2} failed (${httpErr.message}). Attempting in-process gateway dispatch fallback...`);
|
|
4551
4576
|
const _g2 = globalThis;
|
|
4552
4577
|
let dispatch = _g2.__retrivoraDispatchChat;
|
|
4553
4578
|
if (typeof dispatch !== "function") {
|
|
@@ -4562,28 +4587,22 @@ ${context != null ? context : "None"}` },
|
|
|
4562
4587
|
}
|
|
4563
4588
|
}
|
|
4564
4589
|
if (typeof dispatch === "function") {
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
return content;
|
|
4575
|
-
}
|
|
4576
|
-
throw new Error(`[UniversalLLMAdapter] In-process dispatch returned empty content for model: ${this.model}`);
|
|
4577
|
-
} catch (dispatchErr) {
|
|
4578
|
-
throw dispatchErr;
|
|
4590
|
+
const res = await dispatch({
|
|
4591
|
+
model: this.model,
|
|
4592
|
+
messages: formattedMessages,
|
|
4593
|
+
max_tokens: this.maxTokens,
|
|
4594
|
+
temperature: this.temperature
|
|
4595
|
+
}, this.apiKey);
|
|
4596
|
+
const content = extractContent(res == null ? void 0 : res.response);
|
|
4597
|
+
if (content !== void 0) {
|
|
4598
|
+
return content;
|
|
4579
4599
|
}
|
|
4580
|
-
} else {
|
|
4581
|
-
throw new Error(`[UniversalLLMAdapter] In-process gateway dispatch not registered. Direct self-referential HTTP calls to ${this.baseUrl} are disabled on Vercel to prevent HTTP 508 Loop Detected.`);
|
|
4582
4600
|
}
|
|
4601
|
+
throw httpErr;
|
|
4583
4602
|
}
|
|
4584
4603
|
const { data } = await this.http.post(path2, payload);
|
|
4585
|
-
const extractPath = (
|
|
4586
|
-
const result = (
|
|
4604
|
+
const extractPath = (_d = this.opts.responseExtractPath) != null ? _d : "choices[0].message.content";
|
|
4605
|
+
const result = (_e = resolvePath(data, extractPath)) != null ? _e : extractContent(data);
|
|
4587
4606
|
if (result === void 0) {
|
|
4588
4607
|
throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
|
|
4589
4608
|
}
|
|
@@ -4600,12 +4619,16 @@ ${context != null ? context : "None"}` },
|
|
|
4600
4619
|
const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
|
|
4601
4620
|
const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
|
|
4602
4621
|
const extractPath = ((_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content").replace("message.content", "delta.content");
|
|
4622
|
+
const safeMessages = (Array.isArray(messages) ? messages : []).filter((m) => Boolean(m && typeof m === "object")).map((m) => ({
|
|
4623
|
+
role: m.role || "user",
|
|
4624
|
+
content: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : ""
|
|
4625
|
+
}));
|
|
4603
4626
|
const formattedMessages = [
|
|
4604
4627
|
{ role: "system", content: `${this.systemPrompt}
|
|
4605
4628
|
|
|
4606
4629
|
Context:
|
|
4607
4630
|
${context != null ? context : "None"}` },
|
|
4608
|
-
...
|
|
4631
|
+
...safeMessages
|
|
4609
4632
|
];
|
|
4610
4633
|
let payload;
|
|
4611
4634
|
if (this.opts.chatPayloadTemplate) {
|
|
@@ -4721,7 +4744,7 @@ ${context != null ? context : "None"}` },
|
|
|
4721
4744
|
});
|
|
4722
4745
|
}
|
|
4723
4746
|
async embed(text) {
|
|
4724
|
-
var _a2, _b, _c, _d;
|
|
4747
|
+
var _a2, _b, _c, _d, _e;
|
|
4725
4748
|
const path2 = (_a2 = this.opts.embedPath) != null ? _a2 : "/embeddings";
|
|
4726
4749
|
let payload;
|
|
4727
4750
|
if (this.opts.embedPayloadTemplate) {
|
|
@@ -4735,8 +4758,15 @@ ${context != null ? context : "None"}` },
|
|
|
4735
4758
|
input: text
|
|
4736
4759
|
};
|
|
4737
4760
|
}
|
|
4738
|
-
|
|
4739
|
-
|
|
4761
|
+
try {
|
|
4762
|
+
const { data: data2 } = await this.http.post(path2, payload);
|
|
4763
|
+
const extractPath2 = (_b = this.opts.embedExtractPath) != null ? _b : "data[0].embedding";
|
|
4764
|
+
const vector2 = resolvePath(data2, extractPath2);
|
|
4765
|
+
if (Array.isArray(vector2)) {
|
|
4766
|
+
return vector2;
|
|
4767
|
+
}
|
|
4768
|
+
} catch (httpErr) {
|
|
4769
|
+
console.warn(`[UniversalLLMAdapter] Direct HTTP embedding POST to ${this.baseUrl}${path2} failed (${httpErr.message}). Attempting in-process gateway dispatch fallback...`);
|
|
4740
4770
|
const _g2 = globalThis;
|
|
4741
4771
|
let dispatch = _g2.__retrivoraDispatchEmbedding;
|
|
4742
4772
|
if (typeof dispatch !== "function") {
|
|
@@ -4751,24 +4781,18 @@ ${context != null ? context : "None"}` },
|
|
|
4751
4781
|
}
|
|
4752
4782
|
}
|
|
4753
4783
|
if (typeof dispatch === "function") {
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
return res.data[0].embedding;
|
|
4761
|
-
}
|
|
4762
|
-
throw new Error(`[UniversalLLMAdapter] In-process embedding dispatch returned invalid vector for model: ${this.model}`);
|
|
4763
|
-
} catch (dispatchErr) {
|
|
4764
|
-
throw dispatchErr;
|
|
4784
|
+
const res = await dispatch({
|
|
4785
|
+
model: this.model,
|
|
4786
|
+
input: text
|
|
4787
|
+
}, this.apiKey);
|
|
4788
|
+
if ((_d = (_c = res == null ? void 0 : res.data) == null ? void 0 : _c[0]) == null ? void 0 : _d.embedding) {
|
|
4789
|
+
return res.data[0].embedding;
|
|
4765
4790
|
}
|
|
4766
|
-
} else {
|
|
4767
|
-
throw new Error(`[UniversalLLMAdapter] In-process gateway dispatch not registered. Direct self-referential HTTP calls to ${this.baseUrl} are disabled on Vercel to prevent HTTP 508 Loop Detected.`);
|
|
4768
4791
|
}
|
|
4792
|
+
throw httpErr;
|
|
4769
4793
|
}
|
|
4770
4794
|
const { data } = await this.http.post(path2, payload);
|
|
4771
|
-
const extractPath = (
|
|
4795
|
+
const extractPath = (_e = this.opts.embedExtractPath) != null ? _e : "data[0].embedding";
|
|
4772
4796
|
const vector = resolvePath(data, extractPath);
|
|
4773
4797
|
if (!Array.isArray(vector)) {
|
|
4774
4798
|
throw new Error(`[UniversalLLMAdapter] Expected a number array at '${extractPath}' for embeddings.`);
|
|
@@ -6743,8 +6767,8 @@ var IntentClassifier = class {
|
|
|
6743
6767
|
}
|
|
6744
6768
|
// ─── Intent Heuristic Checkers ─────────────────────────────────────────────
|
|
6745
6769
|
static isInformationLookup(query) {
|
|
6746
|
-
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)) {
|
|
6747
|
-
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top selling|best)\b/i.test(query)) {
|
|
6770
|
+
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)) {
|
|
6771
|
+
if (!/\b(compare|versus|vs\.?|trend|monthly|revenue|top 10|top selling|best|chart|graph|plot|breakdown|analytics)\b/i.test(query)) {
|
|
6748
6772
|
return true;
|
|
6749
6773
|
}
|
|
6750
6774
|
}
|
|
@@ -6781,7 +6805,7 @@ var Rule1SpecificInfoRule = class {
|
|
|
6781
6805
|
}
|
|
6782
6806
|
evaluate(context, intent) {
|
|
6783
6807
|
const q = (context.userQuery || "").toLowerCase().trim();
|
|
6784
|
-
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);
|
|
6808
|
+
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);
|
|
6785
6809
|
const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
|
|
6786
6810
|
if (isFactQuery && isNonVisual) {
|
|
6787
6811
|
return {
|
|
@@ -8060,6 +8084,11 @@ ${schemaProfileText}` : ""}`;
|
|
|
8060
8084
|
}
|
|
8061
8085
|
static chooseAutomaticVisualization(data, profile, query) {
|
|
8062
8086
|
if (profile.records.length === 0) return null;
|
|
8087
|
+
const q = query.toLowerCase().trim();
|
|
8088
|
+
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);
|
|
8089
|
+
if (!isExplicitVisualOrAnalytic) {
|
|
8090
|
+
return null;
|
|
8091
|
+
}
|
|
8063
8092
|
if (profile.dateFields.length > 0 && profile.numericFields.length > 0) {
|
|
8064
8093
|
return this.transformToLineChart(profile);
|
|
8065
8094
|
}
|
|
@@ -8175,6 +8204,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8175
8204
|
return Array.from(categories);
|
|
8176
8205
|
}
|
|
8177
8206
|
static getProductCategory(item) {
|
|
8207
|
+
if (!item) return null;
|
|
8178
8208
|
const meta = item.metadata || {};
|
|
8179
8209
|
const metadataCategory = resolveMetadataValue(meta, "category");
|
|
8180
8210
|
if (this.isUsableCategory(metadataCategory)) return String(metadataCategory).trim();
|
|
@@ -8291,6 +8321,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8291
8321
|
if (!fields.has(normalized)) fields.set(normalized, clean);
|
|
8292
8322
|
};
|
|
8293
8323
|
data.forEach((item) => {
|
|
8324
|
+
if (!item) return;
|
|
8294
8325
|
Object.keys(item.metadata || {}).forEach(addField);
|
|
8295
8326
|
for (const match of (item.content || "").matchAll(/(?:^|\n)\s*([A-Za-z][A-Za-z0-9_ /-]{1,50})\s*[:\-–]\s*([^\n]+)/g)) {
|
|
8296
8327
|
addField(match[1]);
|
|
@@ -8407,6 +8438,7 @@ ${schemaProfileText}` : ""}`;
|
|
|
8407
8438
|
return true;
|
|
8408
8439
|
}
|
|
8409
8440
|
static extractStockQuantity(item) {
|
|
8441
|
+
if (!item) return null;
|
|
8410
8442
|
const meta = item.metadata || {};
|
|
8411
8443
|
const stockValue = resolveMetadataValue(meta, "stock");
|
|
8412
8444
|
const numericStock = this.toFiniteNumber(stockValue);
|
|
@@ -9667,7 +9699,10 @@ ${context}`;
|
|
|
9667
9699
|
Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.
|
|
9668
9700
|
|
|
9669
9701
|
History:
|
|
9670
|
-
${history.map((m) =>
|
|
9702
|
+
${(history || []).map((m) => {
|
|
9703
|
+
var _a2;
|
|
9704
|
+
return `${(m == null ? void 0 : m.role) || "user"}: ${(_a2 = m == null ? void 0 : m.content) != null ? _a2 : ""}`;
|
|
9705
|
+
}).join("\n")}
|
|
9671
9706
|
|
|
9672
9707
|
New Question: ${question}
|
|
9673
9708
|
|
|
@@ -9691,8 +9726,11 @@ Optimized Search Query:`;
|
|
|
9691
9726
|
const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
|
|
9692
9727
|
try {
|
|
9693
9728
|
const { sources } = await this.retrieve(query, { namespace: ns, topK: 5 });
|
|
9694
|
-
if (sources.length === 0) return [];
|
|
9695
|
-
const context = sources.map((s) =>
|
|
9729
|
+
if (!sources || sources.length === 0) return [];
|
|
9730
|
+
const context = sources.map((s) => {
|
|
9731
|
+
var _a2;
|
|
9732
|
+
return (_a2 = s == null ? void 0 : s.content) != null ? _a2 : "";
|
|
9733
|
+
}).join("\n\n---\n\n");
|
|
9696
9734
|
const prompt = `Based on the following snippets from a document, what are at least 5 short, relevant questions a user might ask?
|
|
9697
9735
|
Focus on questions that can be answered by the context.
|
|
9698
9736
|
Keep each question under 10 words and make them very specific to the content.
|