@retrivora-ai/rag-engine 2.0.7 → 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/server.js CHANGED
@@ -121,6 +121,617 @@ var init_templateUtils = __esm({
121
121
  }
122
122
  });
123
123
 
124
+ // ../../services/llm-gateway/providers/groq.ts
125
+ async function handleGroqRequest(req, apiKeyOverride) {
126
+ const apiKey = apiKeyOverride || process.env.GROQ_API_KEY;
127
+ if (!apiKey) {
128
+ throw new Error("Groq API Key missing. Please set GROQ_API_KEY in environment variables.");
129
+ }
130
+ const modelName = req.model.replace(/^groq\//i, "");
131
+ const payload = __spreadProps(__spreadValues({}, req), {
132
+ model: modelName
133
+ });
134
+ const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
135
+ method: "POST",
136
+ headers: {
137
+ "Content-Type": "application/json",
138
+ "Authorization": `Bearer ${apiKey}`
139
+ },
140
+ body: JSON.stringify(payload)
141
+ });
142
+ if (!response.ok) {
143
+ const errorText = await response.text();
144
+ throw new Error(`Groq API Error (${response.status}): ${errorText}`);
145
+ }
146
+ if (req.stream && response.body) {
147
+ return { stream: response.body };
148
+ }
149
+ const json = await response.json();
150
+ return { response: json };
151
+ }
152
+ var init_groq = __esm({
153
+ "../../services/llm-gateway/providers/groq.ts"() {
154
+ "use strict";
155
+ }
156
+ });
157
+
158
+ // ../../services/llm-gateway/providers/openai.ts
159
+ async function handleOpenAIRequest(req, apiKeyOverride) {
160
+ const apiKey = apiKeyOverride || process.env.OPENAI_API_KEY;
161
+ if (!apiKey) {
162
+ throw new Error("OpenAI API Key missing. Please set OPENAI_API_KEY in environment variables.");
163
+ }
164
+ const modelName = req.model.replace(/^(openai|gpt)\//i, "");
165
+ const payload = __spreadProps(__spreadValues({}, req), {
166
+ model: modelName
167
+ });
168
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
169
+ method: "POST",
170
+ headers: {
171
+ "Content-Type": "application/json",
172
+ "Authorization": `Bearer ${apiKey}`
173
+ },
174
+ body: JSON.stringify(payload)
175
+ });
176
+ if (!response.ok) {
177
+ const errorText = await response.text();
178
+ throw new Error(`OpenAI API Error (${response.status}): ${errorText}`);
179
+ }
180
+ if (req.stream && response.body) {
181
+ return { stream: response.body };
182
+ }
183
+ const json = await response.json();
184
+ return { response: json };
185
+ }
186
+ async function handleOpenAIEmbedding(req, apiKeyOverride) {
187
+ const apiKey = apiKeyOverride || process.env.OPENAI_API_KEY;
188
+ if (!apiKey) {
189
+ throw new Error("OpenAI API Key missing. Please set OPENAI_API_KEY in environment variables.");
190
+ }
191
+ const modelName = req.model.replace(/^(openai)\//i, "");
192
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
193
+ method: "POST",
194
+ headers: {
195
+ "Content-Type": "application/json",
196
+ "Authorization": `Bearer ${apiKey}`
197
+ },
198
+ body: JSON.stringify({
199
+ model: modelName,
200
+ input: req.input
201
+ })
202
+ });
203
+ if (!response.ok) {
204
+ const errorText = await response.text();
205
+ throw new Error(`OpenAI Embedding API Error (${response.status}): ${errorText}`);
206
+ }
207
+ return await response.json();
208
+ }
209
+ var init_openai = __esm({
210
+ "../../services/llm-gateway/providers/openai.ts"() {
211
+ "use strict";
212
+ }
213
+ });
214
+
215
+ // ../../services/llm-gateway/providers/gemini.ts
216
+ async function handleGeminiRequest(req, apiKeyOverride) {
217
+ const apiKey = apiKeyOverride || process.env.GEMINI_API_KEY;
218
+ if (!apiKey) {
219
+ throw new Error("Gemini API Key missing. Please set GEMINI_API_KEY in environment variables.");
220
+ }
221
+ let modelName = req.model.replace(/^(google|gemini)\//i, "");
222
+ if (!modelName.startsWith("gemini-")) {
223
+ modelName = `gemini-${modelName}`;
224
+ }
225
+ const payload = __spreadProps(__spreadValues({}, req), {
226
+ model: modelName
227
+ });
228
+ const response = await fetch("https://generativelanguage.googleapis.com/v1beta/openai/chat/completions", {
229
+ method: "POST",
230
+ headers: {
231
+ "Content-Type": "application/json",
232
+ "Authorization": `Bearer ${apiKey}`
233
+ },
234
+ body: JSON.stringify(payload)
235
+ });
236
+ if (!response.ok) {
237
+ const errorText = await response.text();
238
+ throw new Error(`Google Gemini API Error (${response.status}): ${errorText}`);
239
+ }
240
+ if (req.stream && response.body) {
241
+ return { stream: response.body };
242
+ }
243
+ const json = await response.json();
244
+ return { response: json };
245
+ }
246
+ async function handleGeminiEmbedding(req, apiKeyOverride) {
247
+ const apiKey = apiKeyOverride || process.env.GEMINI_API_KEY;
248
+ if (!apiKey) {
249
+ throw new Error("Gemini API Key missing. Please set GEMINI_API_KEY in environment variables.");
250
+ }
251
+ let modelName = req.model.replace(/^(google|gemini)\//i, "");
252
+ if (!modelName || modelName === "default" || modelName.includes("text-embedding-3") || modelName.includes("ada") || !modelName.startsWith("text-embedding-00") && !modelName.startsWith("embedding-00")) {
253
+ modelName = "text-embedding-004";
254
+ }
255
+ const response = await fetch("https://generativelanguage.googleapis.com/v1beta/openai/embeddings", {
256
+ method: "POST",
257
+ headers: {
258
+ "Content-Type": "application/json",
259
+ "Authorization": `Bearer ${apiKey}`
260
+ },
261
+ body: JSON.stringify({
262
+ model: modelName,
263
+ input: req.input
264
+ })
265
+ });
266
+ if (!response.ok) {
267
+ const errorText = await response.text();
268
+ throw new Error(`Google Gemini Embedding API Error (${response.status}): ${errorText}`);
269
+ }
270
+ return await response.json();
271
+ }
272
+ var init_gemini = __esm({
273
+ "../../services/llm-gateway/providers/gemini.ts"() {
274
+ "use strict";
275
+ }
276
+ });
277
+
278
+ // ../../services/llm-gateway/providers/huggingface.ts
279
+ async function handleHuggingFaceChatRequest(req, apiKeyOverride) {
280
+ var _a2, _b;
281
+ const apiKey = apiKeyOverride || process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN;
282
+ if (!apiKey) {
283
+ throw new Error("HuggingFace API Key missing. Set HUGGINGFACE_API_KEY or HF_TOKEN in environment variables.");
284
+ }
285
+ let modelName = req.model.replace(/^(huggingface|hf)\//i, "");
286
+ if (!modelName || modelName === "default" || modelName.toLowerCase() === "qwen" || modelName.toLowerCase() === "qwen-coder") {
287
+ modelName = "Qwen/Qwen2.5-Coder-32B-Instruct";
288
+ }
289
+ const payload = __spreadProps(__spreadValues({}, req), {
290
+ model: modelName
291
+ });
292
+ try {
293
+ const response = await fetch("https://router.huggingface.co/v1/chat/completions", {
294
+ method: "POST",
295
+ headers: {
296
+ "Content-Type": "application/json",
297
+ "Authorization": `Bearer ${apiKey}`
298
+ },
299
+ body: JSON.stringify(payload)
300
+ });
301
+ if (response.ok) {
302
+ if (req.stream && response.body) {
303
+ return { stream: response.body };
304
+ }
305
+ const json = await response.json();
306
+ return { response: json };
307
+ }
308
+ } catch (e) {
309
+ }
310
+ try {
311
+ const response = await fetch("https://router.huggingface.co/hf-inference/v1/chat/completions", {
312
+ method: "POST",
313
+ headers: {
314
+ "Content-Type": "application/json",
315
+ "Authorization": `Bearer ${apiKey}`
316
+ },
317
+ body: JSON.stringify(payload)
318
+ });
319
+ if (response.ok) {
320
+ if (req.stream && response.body) {
321
+ return { stream: response.body };
322
+ }
323
+ const json = await response.json();
324
+ return { response: json };
325
+ }
326
+ } catch (e) {
327
+ }
328
+ const lastUserMsg = ((_a2 = req.messages.filter((m) => m.role === "user").pop()) == null ? void 0 : _a2.content) || "Hello";
329
+ const pipelineRes = await fetch(`https://router.huggingface.co/hf-inference/models/${modelName}`, {
330
+ method: "POST",
331
+ headers: {
332
+ "Content-Type": "application/json",
333
+ "Authorization": `Bearer ${apiKey}`
334
+ },
335
+ body: JSON.stringify({
336
+ inputs: lastUserMsg,
337
+ parameters: { max_new_tokens: req.max_tokens || 256, temperature: req.temperature || 0.7 },
338
+ options: { wait_for_model: true }
339
+ })
340
+ });
341
+ if (!pipelineRes.ok) {
342
+ const errorText = await pipelineRes.text();
343
+ throw new Error(`HuggingFace API Error (${pipelineRes.status}): ${errorText}`);
344
+ }
345
+ const raw = await pipelineRes.json();
346
+ const textOutput = Array.isArray(raw) ? ((_b = raw[0]) == null ? void 0 : _b.generated_text) || JSON.stringify(raw) : JSON.stringify(raw);
347
+ const formattedResponse = {
348
+ id: `hf-${Date.now()}`,
349
+ object: "chat.completion",
350
+ created: Math.floor(Date.now() / 1e3),
351
+ model: modelName,
352
+ choices: [
353
+ {
354
+ index: 0,
355
+ message: {
356
+ role: "assistant",
357
+ content: textOutput
358
+ },
359
+ finish_reason: "stop"
360
+ }
361
+ ],
362
+ usage: {
363
+ prompt_tokens: lastUserMsg.length,
364
+ completion_tokens: textOutput.length,
365
+ total_tokens: lastUserMsg.length + textOutput.length
366
+ }
367
+ };
368
+ return { response: formattedResponse };
369
+ }
370
+ async function handleHuggingFaceEmbedding(req, apiKeyOverride) {
371
+ const apiKey = apiKeyOverride || process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN;
372
+ if (!apiKey) {
373
+ throw new Error("HuggingFace API Key missing. Set HUGGINGFACE_API_KEY or HF_TOKEN in environment variables.");
374
+ }
375
+ let modelName = req.model.replace(/^(huggingface|hf)\//i, "");
376
+ if (!modelName || modelName === "default" || modelName.includes("text-embedding-3") || modelName.includes("ada") || !modelName.includes("/") && !modelName.includes("bge") && !modelName.includes("sentence-transformers")) {
377
+ modelName = "BAAI/bge-base-en-v1.5";
378
+ }
379
+ const inputs = Array.isArray(req.input) ? req.input : [req.input];
380
+ const fetchEmbeddingFromModel = async (targetModel) => {
381
+ try {
382
+ const routerRes = await fetch("https://router.huggingface.co/hf-inference/v1/embeddings", {
383
+ method: "POST",
384
+ headers: {
385
+ "Content-Type": "application/json",
386
+ "Authorization": `Bearer ${apiKey}`
387
+ },
388
+ body: JSON.stringify({
389
+ model: targetModel,
390
+ input: inputs
391
+ })
392
+ });
393
+ if (routerRes.ok) {
394
+ const json = await routerRes.json();
395
+ if (json && json.data) return json;
396
+ }
397
+ } catch (e) {
398
+ }
399
+ const response = await fetch(`https://router.huggingface.co/hf-inference/models/${targetModel}`, {
400
+ method: "POST",
401
+ headers: {
402
+ "Content-Type": "application/json",
403
+ "Authorization": `Bearer ${apiKey}`
404
+ },
405
+ body: JSON.stringify({
406
+ inputs,
407
+ options: { wait_for_model: true }
408
+ })
409
+ });
410
+ if (!response.ok) {
411
+ const errorText = await response.text();
412
+ throw new Error(`HuggingFace API Error (${response.status}): ${errorText}`);
413
+ }
414
+ const rawData = await response.json();
415
+ const embeddings = Array.isArray(rawData[0]) ? typeof rawData[0][0] === "number" ? rawData : rawData.map((arr) => arr[0]) : [rawData];
416
+ return {
417
+ object: "list",
418
+ data: embeddings.map((vec, idx) => ({
419
+ object: "embedding",
420
+ embedding: vec,
421
+ index: idx
422
+ })),
423
+ model: targetModel,
424
+ usage: {
425
+ prompt_tokens: inputs.reduce((acc, str) => acc + str.length, 0),
426
+ completion_tokens: 0,
427
+ total_tokens: inputs.reduce((acc, str) => acc + str.length, 0)
428
+ }
429
+ };
430
+ };
431
+ try {
432
+ return await fetchEmbeddingFromModel(modelName);
433
+ } catch (err) {
434
+ if (modelName !== "BAAI/bge-base-en-v1.5") {
435
+ console.warn(`[LLM Gateway] HuggingFace model ${modelName} failed. Falling back to BAAI/bge-base-en-v1.5...`, err);
436
+ return await fetchEmbeddingFromModel("BAAI/bge-base-en-v1.5");
437
+ }
438
+ throw err;
439
+ }
440
+ }
441
+ var init_huggingface = __esm({
442
+ "../../services/llm-gateway/providers/huggingface.ts"() {
443
+ "use strict";
444
+ }
445
+ });
446
+
447
+ // ../../services/llm-gateway/providers/anthropic.ts
448
+ async function handleAnthropicRequest(req, apiKeyOverride) {
449
+ var _a2, _b;
450
+ const apiKey = apiKeyOverride || process.env.ANTHROPIC_API_KEY;
451
+ if (!apiKey) {
452
+ throw new Error("Anthropic API Key missing. Please set ANTHROPIC_API_KEY in environment variables.");
453
+ }
454
+ const modelName = req.model.replace(/^(anthropic|claude)\//i, "");
455
+ let systemPrompt = void 0;
456
+ const anthropicMessages = [];
457
+ for (const msg of req.messages) {
458
+ if (msg.role === "system") {
459
+ systemPrompt = systemPrompt ? `${systemPrompt}
460
+ ${msg.content}` : msg.content;
461
+ } else {
462
+ anthropicMessages.push({
463
+ role: msg.role === "assistant" ? "assistant" : "user",
464
+ content: msg.content
465
+ });
466
+ }
467
+ }
468
+ if (anthropicMessages.length === 0) {
469
+ anthropicMessages.push({ role: "user", content: "Hello" });
470
+ }
471
+ const payload = {
472
+ model: modelName,
473
+ messages: anthropicMessages,
474
+ max_tokens: req.max_tokens || req.max_completion_tokens || 1024,
475
+ stream: req.stream || false
476
+ };
477
+ if (systemPrompt) {
478
+ payload.system = systemPrompt;
479
+ }
480
+ if (req.temperature !== void 0) {
481
+ payload.temperature = req.temperature;
482
+ }
483
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
484
+ method: "POST",
485
+ headers: {
486
+ "Content-Type": "application/json",
487
+ "x-api-key": apiKey,
488
+ "anthropic-version": "2023-06-01"
489
+ },
490
+ body: JSON.stringify(payload)
491
+ });
492
+ if (!response.ok) {
493
+ const errorText = await response.text();
494
+ throw new Error(`Anthropic API Error (${response.status}): ${errorText}`);
495
+ }
496
+ if (req.stream && response.body) {
497
+ return { stream: response.body };
498
+ }
499
+ const json = await response.json();
500
+ const textContent = ((_b = (_a2 = json.content) == null ? void 0 : _a2[0]) == null ? void 0 : _b.text) || "";
501
+ const openAIResponse = {
502
+ id: json.id || `chatcmpl-${Date.now()}`,
503
+ object: "chat.completion",
504
+ created: Math.floor(Date.now() / 1e3),
505
+ model: json.model || modelName,
506
+ choices: [
507
+ {
508
+ index: 0,
509
+ message: {
510
+ role: "assistant",
511
+ content: textContent
512
+ },
513
+ finish_reason: json.stop_reason === "end_turn" ? "stop" : json.stop_reason || "stop"
514
+ }
515
+ ],
516
+ usage: json.usage ? {
517
+ prompt_tokens: json.usage.input_tokens,
518
+ completion_tokens: json.usage.output_tokens,
519
+ total_tokens: json.usage.input_tokens + json.usage.output_tokens
520
+ } : void 0
521
+ };
522
+ return { response: openAIResponse };
523
+ }
524
+ var init_anthropic = __esm({
525
+ "../../services/llm-gateway/providers/anthropic.ts"() {
526
+ "use strict";
527
+ }
528
+ });
529
+
530
+ // ../../services/llm-gateway/providers/ollama.ts
531
+ async function handleOllamaRequest(req, baseUrlOverride) {
532
+ const baseUrl = (baseUrlOverride || process.env.OLLAMA_BASE_URL || "http://localhost:11434/v1").replace(/\/+$/, "");
533
+ const modelName = req.model.replace(/^ollama\//i, "");
534
+ const payload = __spreadProps(__spreadValues({}, req), {
535
+ model: modelName
536
+ });
537
+ const response = await fetch(`${baseUrl}/chat/completions`, {
538
+ method: "POST",
539
+ headers: {
540
+ "Content-Type": "application/json"
541
+ },
542
+ body: JSON.stringify(payload)
543
+ });
544
+ if (!response.ok) {
545
+ const errorText = await response.text();
546
+ throw new Error(`Ollama API Error (${response.status}): ${errorText}`);
547
+ }
548
+ if (req.stream && response.body) {
549
+ return { stream: response.body };
550
+ }
551
+ const json = await response.json();
552
+ return { response: json };
553
+ }
554
+ var init_ollama = __esm({
555
+ "../../services/llm-gateway/providers/ollama.ts"() {
556
+ "use strict";
557
+ }
558
+ });
559
+
560
+ // ../../services/llm-gateway/router.ts
561
+ var router_exports = {};
562
+ __export(router_exports, {
563
+ SUPPORTED_MODELS: () => SUPPORTED_MODELS,
564
+ dispatchChatCompletion: () => dispatchChatCompletion,
565
+ dispatchEmbedding: () => dispatchEmbedding,
566
+ resolveProvider: () => resolveProvider
567
+ });
568
+ function resolveProvider(model) {
569
+ const lower = model.toLowerCase();
570
+ if (lower.startsWith("huggingface/") || lower.startsWith("hf/")) {
571
+ return "huggingface";
572
+ }
573
+ if (lower.startsWith("ollama/")) {
574
+ return "ollama";
575
+ }
576
+ if (lower.startsWith("groq/") || lower.includes("llama") || lower.includes("qwen") || lower.includes("mixtral")) {
577
+ return "groq";
578
+ }
579
+ if (process.env.GROQ_API_KEY) return "groq";
580
+ if (process.env.OPENAI_API_KEY) return "openai";
581
+ if (process.env.GEMINI_API_KEY) return "gemini";
582
+ if (process.env.ANTHROPIC_API_KEY) return "anthropic";
583
+ if (process.env.HF_TOKEN || process.env.HUGGINGFACE_API_KEY) return "huggingface";
584
+ return "groq";
585
+ }
586
+ function cleanApiKeyOverride(apiKeyOverride) {
587
+ if (!apiKeyOverride) return void 0;
588
+ const key = apiKeyOverride.trim();
589
+ if (key === process.env.LITELLM_API_KEY || key === process.env.LITELLM_MASTER_KEY || key.startsWith("sk-retrivora") || !key.startsWith("gsk_") && !key.startsWith("AIza") && !key.startsWith("sk-ant-") && !key.startsWith("sk-proj-")) {
590
+ return void 0;
591
+ }
592
+ return key;
593
+ }
594
+ async function dispatchChatCompletion(req, apiKeyOverride) {
595
+ const effectiveKey = cleanApiKeyOverride(apiKeyOverride);
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)}`);
598
+ try {
599
+ switch (provider) {
600
+ case "groq":
601
+ return await handleGroqRequest(req, effectiveKey);
602
+ case "openai":
603
+ return await handleOpenAIRequest(req, effectiveKey);
604
+ case "gemini":
605
+ return await handleGeminiRequest(req, effectiveKey);
606
+ case "anthropic":
607
+ return await handleAnthropicRequest(req, effectiveKey);
608
+ case "ollama":
609
+ return await handleOllamaRequest(req);
610
+ case "huggingface":
611
+ return await handleHuggingFaceChatRequest(req, effectiveKey);
612
+ default:
613
+ throw new Error(`Unsupported LLM provider for model: ${req.model}`);
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
+ });
620
+ if (/rate[- ]?limit|429|exhausted/i.test(error.message)) {
621
+ const isGroqKey = process.env.GROQ_API_KEY || effectiveKey && effectiveKey.startsWith("gsk_");
622
+ const reqModelLower = req.model.toLowerCase();
623
+ if (isGroqKey && !reqModelLower.includes("llama-3.3-70b")) {
624
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to secondary Groq model (llama-3.3-70b-versatile)...`);
625
+ try {
626
+ return await handleGroqRequest(__spreadProps(__spreadValues({}, req), { model: "llama-3.3-70b-versatile" }), effectiveKey);
627
+ } catch (fErr) {
628
+ console.error("[LLM Gateway] Fallback groq/llama-3.3-70b-versatile failed:", fErr.message);
629
+ }
630
+ }
631
+ const geminiKey = process.env.GEMINI_API_KEY || effectiveKey;
632
+ if (provider !== "gemini" && geminiKey && (geminiKey.startsWith("AIza") || !geminiKey.startsWith("AQ."))) {
633
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Google Gemini (gemini-2.5-flash)...`);
634
+ try {
635
+ return await handleGeminiRequest(__spreadProps(__spreadValues({}, req), { model: "gemini-2.5-flash" }), effectiveKey);
636
+ } catch (fErr) {
637
+ console.error("[LLM Gateway] Fallback gemini-2.5-flash failed:", fErr.message);
638
+ }
639
+ }
640
+ if (provider !== "huggingface" && (process.env.HF_TOKEN || process.env.HUGGINGFACE_API_KEY)) {
641
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Hugging Face (Qwen/Qwen2.5-Coder-32B-Instruct)...`);
642
+ try {
643
+ return await handleHuggingFaceChatRequest(__spreadProps(__spreadValues({}, req), { model: "Qwen/Qwen2.5-Coder-32B-Instruct" }), effectiveKey);
644
+ } catch (fErr) {
645
+ console.error("[LLM Gateway] Fallback HuggingFace Qwen failed:", fErr.message);
646
+ }
647
+ }
648
+ if (provider !== "openai" && process.env.OPENAI_API_KEY) {
649
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to OpenAI (gpt-4o-mini)...`);
650
+ try {
651
+ return await handleOpenAIRequest(__spreadProps(__spreadValues({}, req), { model: "gpt-4o-mini" }), effectiveKey);
652
+ } catch (e) {
653
+ }
654
+ }
655
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to local Ollama (llama3.2)...`);
656
+ return handleOllamaRequest(__spreadProps(__spreadValues({}, req), { model: "llama3.2" }));
657
+ }
658
+ throw error;
659
+ }
660
+ }
661
+ async function dispatchEmbedding(req, apiKeyOverride) {
662
+ const effectiveKey = cleanApiKeyOverride(apiKeyOverride);
663
+ if (req.model.startsWith("hf/") || req.model.startsWith("huggingface/") || req.model.includes("bge-")) {
664
+ try {
665
+ return await handleHuggingFaceEmbedding(req, effectiveKey);
666
+ } catch (err) {
667
+ console.warn("[LLM Gateway] HuggingFace explicit model embedding failed, falling back to default gateway chain:", err);
668
+ }
669
+ }
670
+ const geminiKey = process.env.GEMINI_API_KEY || effectiveKey;
671
+ const isGeminiKeyValid = Boolean(geminiKey && (geminiKey.startsWith("AIza") || !geminiKey.startsWith("AQ.")));
672
+ if (isGeminiKeyValid) {
673
+ try {
674
+ return await handleGeminiEmbedding(req, effectiveKey);
675
+ } catch (err) {
676
+ console.warn("[LLM Gateway] Gemini embedding failed:", err);
677
+ }
678
+ }
679
+ if (process.env.OPENAI_API_KEY) {
680
+ try {
681
+ return await handleOpenAIEmbedding(req, effectiveKey);
682
+ } catch (err) {
683
+ console.warn("[LLM Gateway] OpenAI embedding failed:", err);
684
+ }
685
+ }
686
+ if (process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN) {
687
+ try {
688
+ return await handleHuggingFaceEmbedding(req, effectiveKey);
689
+ } catch (err) {
690
+ console.warn("[LLM Gateway] HuggingFace fallback embedding failed:", err);
691
+ }
692
+ }
693
+ return handleGeminiEmbedding(req, effectiveKey);
694
+ }
695
+ var SUPPORTED_MODELS;
696
+ var init_router = __esm({
697
+ "../../services/llm-gateway/router.ts"() {
698
+ "use strict";
699
+ init_groq();
700
+ init_openai();
701
+ init_gemini();
702
+ init_huggingface();
703
+ init_anthropic();
704
+ init_ollama();
705
+ SUPPORTED_MODELS = [
706
+ { id: "groq/llama-3.1-8b-instant", object: "model", created: 17e8, owned_by: "groq" },
707
+ { id: "llama-3.1-8b-instant", object: "model", created: 17e8, owned_by: "groq" },
708
+ { id: "groq/llama-3.3-70b-versatile", object: "model", created: 17e8, owned_by: "groq" },
709
+ { id: "llama-3.3-70b-versatile", object: "model", created: 17e8, owned_by: "groq" },
710
+ { id: "gpt-4o-mini", object: "model", created: 17e8, owned_by: "openai" },
711
+ { id: "openai/gpt-4o-mini", object: "model", created: 17e8, owned_by: "openai" },
712
+ { id: "gpt-4o", object: "model", created: 17e8, owned_by: "openai" },
713
+ { id: "gemini-2.5-flash", object: "model", created: 17e8, owned_by: "google" },
714
+ { id: "google/gemini-2.5-flash", object: "model", created: 17e8, owned_by: "google" },
715
+ { id: "claude-3-5-haiku-20241022", object: "model", created: 17e8, owned_by: "anthropic" },
716
+ { id: "anthropic/claude-3-5-haiku-20241022", object: "model", created: 17e8, owned_by: "anthropic" },
717
+ { id: "text-embedding-004", object: "model", created: 17e8, owned_by: "google" },
718
+ { id: "google/text-embedding-004", object: "model", created: 17e8, owned_by: "google" },
719
+ { id: "BAAI/bge-base-en-v1.5", object: "model", created: 17e8, owned_by: "huggingface" },
720
+ { id: "huggingface/BAAI/bge-base-en-v1.5", object: "model", created: 17e8, owned_by: "huggingface" },
721
+ { id: "groq/qwen3-32b", object: "model", created: 17e8, owned_by: "groq" },
722
+ { id: "qwen/qwen3-32b", object: "model", created: 17e8, owned_by: "groq" },
723
+ { id: "qwen/qwen3-embedding-8b", object: "model", created: 17e8, owned_by: "qwen" },
724
+ { id: "qwen3-embedding-8b", object: "model", created: 17e8, owned_by: "qwen" },
725
+ { id: "ollama/llama3.2", object: "model", created: 17e8, owned_by: "ollama" }
726
+ ];
727
+ if (typeof globalThis !== "undefined") {
728
+ const _g2 = globalThis;
729
+ _g2.__retrivoraDispatchChat = dispatchChatCompletion;
730
+ _g2.__retrivoraDispatchEmbedding = dispatchEmbedding;
731
+ }
732
+ }
733
+ });
734
+
124
735
  // src/providers/vectordb/BaseVectorProvider.ts
125
736
  var BaseVectorProvider;
126
737
  var init_BaseVectorProvider = __esm({
@@ -2886,12 +3497,13 @@ var OpenAIProvider = class {
2886
3497
  role: "system",
2887
3498
  content: buildSystemContent(basePrompt, context)
2888
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
+ }));
2889
3504
  const formattedMessages = [
2890
3505
  systemMessage,
2891
- ...messages.map((m) => ({
2892
- role: m.role,
2893
- content: m.content
2894
- }))
3506
+ ...safeMessages
2895
3507
  ];
2896
3508
  const completion = await this.client.chat.completions.create({
2897
3509
  model: this.llmConfig.model,
@@ -2910,12 +3522,13 @@ var OpenAIProvider = class {
2910
3522
  role: "system",
2911
3523
  content: buildSystemContent(basePrompt, context)
2912
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
+ }));
2913
3529
  const formattedMessages = [
2914
3530
  systemMessage,
2915
- ...messages.map((m) => ({
2916
- role: m.role,
2917
- content: m.content
2918
- }))
3531
+ ...safeStreamMessages
2919
3532
  ];
2920
3533
  const stream = yield new __await(this.client.chat.completions.create({
2921
3534
  model: this.llmConfig.model,
@@ -3446,9 +4059,9 @@ var GeminiProvider = class {
3446
4059
  * - Messages must strictly alternate between `user` and `model`.
3447
4060
  */
3448
4061
  buildGeminiContents(messages) {
3449
- return messages.filter((m) => m.role !== "system").map((m) => ({
4062
+ return (messages || []).filter((m) => Boolean(m && typeof m === "object" && m.role !== "system")).map((m) => ({
3450
4063
  role: m.role === "assistant" ? "model" : "user",
3451
- parts: [{ text: m.content }]
4064
+ parts: [{ text: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : "" }]
3452
4065
  }));
3453
4066
  }
3454
4067
  // -------------------------------------------------------------------------
@@ -3651,12 +4264,13 @@ var GroqProvider = class {
3651
4264
  role: "system",
3652
4265
  content: buildSystemContent(basePrompt, context)
3653
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
+ }));
3654
4271
  const formattedMessages = [
3655
4272
  systemMessage,
3656
- ...messages.map((m) => ({
3657
- role: m.role,
3658
- content: m.content
3659
- }))
4273
+ ...safeMessages
3660
4274
  ];
3661
4275
  const completion = await this.client.chat.completions.create({
3662
4276
  model: this.llmConfig.model,
@@ -3675,12 +4289,13 @@ var GroqProvider = class {
3675
4289
  role: "system",
3676
4290
  content: buildSystemContent(basePrompt, context)
3677
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
+ }));
3678
4296
  const formattedMessages = [
3679
4297
  systemMessage,
3680
- ...messages.map((m) => ({
3681
- role: m.role,
3682
- content: m.content
3683
- }))
4298
+ ...safeStreamMessages
3684
4299
  ];
3685
4300
  const stream = yield new __await(this.client.chat.completions.create({
3686
4301
  model: this.llmConfig.model,
@@ -3809,12 +4424,13 @@ var QwenProvider = class {
3809
4424
  role: "system",
3810
4425
  content: buildSystemContent(basePrompt, context)
3811
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
+ }));
3812
4431
  const formattedMessages = [
3813
4432
  systemMessage,
3814
- ...messages.map((m) => ({
3815
- role: m.role,
3816
- content: m.content
3817
- }))
4433
+ ...safeMessages
3818
4434
  ];
3819
4435
  const completion = await this.client.chat.completions.create({
3820
4436
  model: this.llmConfig.model,
@@ -3833,12 +4449,13 @@ var QwenProvider = class {
3833
4449
  role: "system",
3834
4450
  content: buildSystemContent(basePrompt, context)
3835
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
+ }));
3836
4456
  const formattedMessages = [
3837
4457
  systemMessage,
3838
- ...messages.map((m) => ({
3839
- role: m.role,
3840
- content: m.content
3841
- }))
4458
+ ...safeStreamMessages
3842
4459
  ];
3843
4460
  const stream = yield new __await(this.client.chat.completions.create({
3844
4461
  model: this.llmConfig.model,
@@ -3976,6 +4593,17 @@ var VECTOR_PROFILES = {
3976
4593
  };
3977
4594
 
3978
4595
  // src/llm/providers/UniversalLLMAdapter.ts
4596
+ function extractContent(obj) {
4597
+ var _a2, _b, _c;
4598
+ if (!obj || typeof obj !== "object") return void 0;
4599
+ const choice = (_a2 = obj.choices) == null ? void 0 : _a2[0];
4600
+ if (!choice) return void 0;
4601
+ if (typeof ((_b = choice.message) == null ? void 0 : _b.content) === "string") return choice.message.content;
4602
+ if (typeof ((_c = choice.delta) == null ? void 0 : _c.content) === "string") return choice.delta.content;
4603
+ if (typeof choice.text === "string") return choice.text;
4604
+ if (typeof choice.content === "string") return choice.content;
4605
+ return void 0;
4606
+ }
3979
4607
  var UniversalLLMAdapter = class {
3980
4608
  constructor(config) {
3981
4609
  var _a2, _b, _c, _d, _e, _f, _g2, _h;
@@ -4007,14 +4635,18 @@ var UniversalLLMAdapter = class {
4007
4635
  });
4008
4636
  }
4009
4637
  async chat(messages, context) {
4010
- var _a2, _b, _c, _d, _e, _f;
4638
+ var _a2, _b, _c;
4011
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
+ }));
4012
4644
  const formattedMessages = [
4013
4645
  { role: "system", content: `${this.systemPrompt}
4014
4646
 
4015
4647
  Context:
4016
4648
  ${context != null ? context : "None"}` },
4017
- ...messages
4649
+ ...safeMessages
4018
4650
  ];
4019
4651
  let payload;
4020
4652
  if (this.opts.chatPayloadTemplate) {
@@ -4035,25 +4667,41 @@ ${context != null ? context : "None"}` },
4035
4667
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4036
4668
  if (isSelfHost || Boolean(process.env.VERCEL)) {
4037
4669
  const _g2 = globalThis;
4038
- if (typeof _g2.__retrivoraDispatchChat === "function") {
4670
+ let dispatch = _g2.__retrivoraDispatchChat;
4671
+ if (typeof dispatch !== "function") {
4039
4672
  try {
4040
- const res = await _g2.__retrivoraDispatchChat({
4673
+ const gateway = await Promise.resolve().then(() => (init_router(), router_exports));
4674
+ if (gateway == null ? void 0 : gateway.dispatchChatCompletion) {
4675
+ _g2.__retrivoraDispatchChat = gateway.dispatchChatCompletion;
4676
+ _g2.__retrivoraDispatchEmbedding = gateway.dispatchEmbedding;
4677
+ dispatch = gateway.dispatchChatCompletion;
4678
+ }
4679
+ } catch (e) {
4680
+ }
4681
+ }
4682
+ if (typeof dispatch === "function") {
4683
+ try {
4684
+ const res = await dispatch({
4041
4685
  model: this.model,
4042
4686
  messages: formattedMessages,
4043
4687
  max_tokens: this.maxTokens,
4044
4688
  temperature: this.temperature
4045
4689
  }, 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;
4690
+ const content = extractContent(res == null ? void 0 : res.response);
4691
+ if (content !== void 0) {
4692
+ return content;
4048
4693
  }
4694
+ throw new Error(`[UniversalLLMAdapter] In-process dispatch returned empty content for model: ${this.model}`);
4049
4695
  } catch (dispatchErr) {
4050
4696
  throw dispatchErr;
4051
4697
  }
4698
+ } else {
4699
+ 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.`);
4052
4700
  }
4053
4701
  }
4054
4702
  const { data } = await this.http.post(path2, payload);
4055
- const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
4056
- const result = resolvePath(data, extractPath);
4703
+ const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
4704
+ const result = (_c = resolvePath(data, extractPath)) != null ? _c : extractContent(data);
4057
4705
  if (result === void 0) {
4058
4706
  throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
4059
4707
  }
@@ -4066,16 +4714,20 @@ ${context != null ? context : "None"}` },
4066
4714
  */
4067
4715
  chatStream(messages, context) {
4068
4716
  return __asyncGenerator(this, null, function* () {
4069
- var _a2, _b, _c, _d, _e, _f, _g2;
4717
+ var _a2, _b, _c, _d, _e;
4070
4718
  const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
4071
4719
  const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
4072
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
+ }));
4073
4725
  const formattedMessages = [
4074
4726
  { role: "system", content: `${this.systemPrompt}
4075
4727
 
4076
4728
  Context:
4077
4729
  ${context != null ? context : "None"}` },
4078
- ...messages
4730
+ ...safeMessages
4079
4731
  ];
4080
4732
  let payload;
4081
4733
  if (this.opts.chatPayloadTemplate) {
@@ -4100,10 +4752,22 @@ ${context != null ? context : "None"}` },
4100
4752
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4101
4753
  let streamBody = null;
4102
4754
  if (isSelfHost || Boolean(process.env.VERCEL)) {
4103
- const _g3 = globalThis;
4104
- if (typeof _g3.__retrivoraDispatchChat === "function") {
4755
+ const _g2 = globalThis;
4756
+ let dispatch = _g2.__retrivoraDispatchChat;
4757
+ if (typeof dispatch !== "function") {
4105
4758
  try {
4106
- const res = yield new __await(_g3.__retrivoraDispatchChat({
4759
+ const gateway = yield new __await(Promise.resolve().then(() => (init_router(), router_exports)));
4760
+ if (gateway == null ? void 0 : gateway.dispatchChatCompletion) {
4761
+ _g2.__retrivoraDispatchChat = gateway.dispatchChatCompletion;
4762
+ _g2.__retrivoraDispatchEmbedding = gateway.dispatchEmbedding;
4763
+ dispatch = gateway.dispatchChatCompletion;
4764
+ }
4765
+ } catch (e) {
4766
+ }
4767
+ }
4768
+ if (typeof dispatch === "function") {
4769
+ try {
4770
+ const res = yield new __await(dispatch({
4107
4771
  model: this.model,
4108
4772
  messages: formattedMessages,
4109
4773
  max_tokens: this.maxTokens,
@@ -4112,13 +4776,19 @@ ${context != null ? context : "None"}` },
4112
4776
  }, this.apiKey));
4113
4777
  if (res == null ? void 0 : res.stream) {
4114
4778
  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;
4779
+ } else {
4780
+ const content = extractContent(res == null ? void 0 : res.response);
4781
+ if (content !== void 0) {
4782
+ yield content;
4783
+ return;
4784
+ }
4785
+ throw new Error(`[UniversalLLMAdapter] In-process dispatch stream returned empty response for model: ${this.model}`);
4118
4786
  }
4119
4787
  } catch (dispatchErr) {
4120
4788
  throw dispatchErr;
4121
4789
  }
4790
+ } else {
4791
+ 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.`);
4122
4792
  }
4123
4793
  }
4124
4794
  if (!streamBody) {
@@ -4145,14 +4815,14 @@ ${context != null ? context : "None"}` },
4145
4815
  if (done) break;
4146
4816
  buffer += decoder.decode(value, { stream: true });
4147
4817
  const lines = buffer.split("\n");
4148
- buffer = (_g2 = lines.pop()) != null ? _g2 : "";
4818
+ buffer = (_c = lines.pop()) != null ? _c : "";
4149
4819
  for (const line of lines) {
4150
4820
  const trimmed = line.trim();
4151
4821
  if (!trimmed || trimmed === "data: [DONE]") continue;
4152
4822
  if (!trimmed.startsWith("data:")) continue;
4153
4823
  try {
4154
4824
  const json = JSON.parse(trimmed.slice(5).trim());
4155
- const text = resolvePath(json, extractPath);
4825
+ const text = (_d = resolvePath(json, extractPath)) != null ? _d : extractContent(json);
4156
4826
  if (text && typeof text === "string") yield text;
4157
4827
  } catch (e) {
4158
4828
  }
@@ -4162,7 +4832,7 @@ ${context != null ? context : "None"}` },
4162
4832
  const jsonStr = buffer.replace(/^data:\s*/, "").trim();
4163
4833
  try {
4164
4834
  const json = JSON.parse(jsonStr);
4165
- const text = resolvePath(json, extractPath);
4835
+ const text = (_e = resolvePath(json, extractPath)) != null ? _e : extractContent(json);
4166
4836
  if (text && typeof text === "string") yield text;
4167
4837
  } catch (e) {
4168
4838
  }
@@ -4190,18 +4860,33 @@ ${context != null ? context : "None"}` },
4190
4860
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4191
4861
  if (isSelfHost || Boolean(process.env.VERCEL)) {
4192
4862
  const _g2 = globalThis;
4193
- if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
4863
+ let dispatch = _g2.__retrivoraDispatchEmbedding;
4864
+ if (typeof dispatch !== "function") {
4194
4865
  try {
4195
- const res = await _g2.__retrivoraDispatchEmbedding({
4866
+ const gateway = await Promise.resolve().then(() => (init_router(), router_exports));
4867
+ if (gateway == null ? void 0 : gateway.dispatchEmbedding) {
4868
+ _g2.__retrivoraDispatchChat = gateway.dispatchChatCompletion;
4869
+ _g2.__retrivoraDispatchEmbedding = gateway.dispatchEmbedding;
4870
+ dispatch = gateway.dispatchEmbedding;
4871
+ }
4872
+ } catch (e) {
4873
+ }
4874
+ }
4875
+ if (typeof dispatch === "function") {
4876
+ try {
4877
+ const res = await dispatch({
4196
4878
  model: this.model,
4197
4879
  input: text
4198
4880
  }, this.apiKey);
4199
4881
  if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
4200
4882
  return res.data[0].embedding;
4201
4883
  }
4884
+ throw new Error(`[UniversalLLMAdapter] In-process embedding dispatch returned invalid vector for model: ${this.model}`);
4202
4885
  } catch (dispatchErr) {
4203
4886
  throw dispatchErr;
4204
4887
  }
4888
+ } else {
4889
+ 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.`);
4205
4890
  }
4206
4891
  }
4207
4892
  const { data } = await this.http.post(path2, payload);
@@ -6186,8 +6871,8 @@ var IntentClassifier = class {
6186
6871
  }
6187
6872
  // ─── Intent Heuristic Checkers ─────────────────────────────────────────────
6188
6873
  static isInformationLookup(query) {
6189
- 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)) {
6190
- 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)) {
6191
6876
  return true;
6192
6877
  }
6193
6878
  }
@@ -6224,7 +6909,7 @@ var Rule1SpecificInfoRule = class {
6224
6909
  }
6225
6910
  evaluate(context, intent) {
6226
6911
  const q = (context.userQuery || "").toLowerCase().trim();
6227
- 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);
6228
6913
  const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
6229
6914
  if (isFactQuery && isNonVisual) {
6230
6915
  return {
@@ -7063,7 +7748,7 @@ ${schemaProfileText}` : ""}`;
7063
7748
  }
7064
7749
  // ─── Transform Helpers ────────────────────────────────────────────────────
7065
7750
  static transformToProductCarousel(data, config, trainedSchema) {
7066
- const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null).slice(0, 15);
7751
+ const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null);
7067
7752
  return {
7068
7753
  type: "product_carousel",
7069
7754
  title: "Recommended Products",
@@ -7443,7 +8128,8 @@ ${schemaProfileText}` : ""}`;
7443
8128
  return fieldCount.size > 2;
7444
8129
  }
7445
8130
  static profileData(data) {
7446
- const records = data.map((item) => {
8131
+ const records = (data || []).filter((item) => Boolean(item && typeof item === "object")).map((item) => {
8132
+ var _a2, _b;
7447
8133
  const fields2 = {};
7448
8134
  Object.entries(item.metadata || {}).forEach(([key, value]) => {
7449
8135
  const primitive = this.toPrimitive(value);
@@ -7452,8 +8138,8 @@ ${schemaProfileText}` : ""}`;
7452
8138
  if (!fields2.content && item.content) fields2.content = item.content.substring(0, 500);
7453
8139
  return {
7454
8140
  id: item.id,
7455
- content: item.content,
7456
- score: item.score,
8141
+ content: (_a2 = item.content) != null ? _a2 : "",
8142
+ score: (_b = item.score) != null ? _b : 0,
7457
8143
  fields: fields2,
7458
8144
  source: item
7459
8145
  };
@@ -7510,6 +8196,11 @@ ${schemaProfileText}` : ""}`;
7510
8196
  }
7511
8197
  static chooseAutomaticVisualization(data, profile, query) {
7512
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
+ }
7513
8204
  if (profile.dateFields.length > 0 && profile.numericFields.length > 0) {
7514
8205
  return this.transformToLineChart(profile);
7515
8206
  }
@@ -7625,6 +8316,7 @@ ${schemaProfileText}` : ""}`;
7625
8316
  return Array.from(categories);
7626
8317
  }
7627
8318
  static getProductCategory(item) {
8319
+ if (!item) return null;
7628
8320
  const meta = item.metadata || {};
7629
8321
  const metadataCategory = resolveMetadataValue(meta, "category");
7630
8322
  if (this.isUsableCategory(metadataCategory)) return String(metadataCategory).trim();
@@ -7741,6 +8433,7 @@ ${schemaProfileText}` : ""}`;
7741
8433
  if (!fields.has(normalized)) fields.set(normalized, clean);
7742
8434
  };
7743
8435
  data.forEach((item) => {
8436
+ if (!item) return;
7744
8437
  Object.keys(item.metadata || {}).forEach(addField);
7745
8438
  for (const match of (item.content || "").matchAll(/(?:^|\n)\s*([A-Za-z][A-Za-z0-9_ /-]{1,50})\s*[:\-–]\s*([^\n]+)/g)) {
7746
8439
  addField(match[1]);
@@ -7857,6 +8550,7 @@ ${schemaProfileText}` : ""}`;
7857
8550
  return true;
7858
8551
  }
7859
8552
  static extractStockQuantity(item) {
8553
+ if (!item) return null;
7860
8554
  const meta = item.metadata || {};
7861
8555
  const stockValue = resolveMetadataValue(meta, "stock");
7862
8556
  const numericStock = this.toFiniteNumber(stockValue);
@@ -8556,7 +9250,7 @@ ${m.content}`).join("\n\n---\n\n");
8556
9250
  */
8557
9251
  askStreamInternal(_0) {
8558
9252
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
8559
- var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
9253
+ var _a2, _b, _c, _d, _e, _f, _g2, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B;
8560
9254
  yield new __await(this.initialize());
8561
9255
  const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
8562
9256
  const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
@@ -8599,8 +9293,8 @@ ${m.content}`).join("\n\n---\n\n");
8599
9293
  const graphData = (strategyResult === "graph" || strategyResult === "both") && this.graphDB && ((_l = this.config.rag) == null ? void 0 : _l.useGraphRetrieval) ? yield new __await(this.graphDB.query(searchQuery)) : void 0;
8600
9294
  const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
8601
9295
  const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
8602
- const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
8603
- const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
9296
+ const wantsExhaustiveList = true;
9297
+ const retrievalLimit = Math.max(topK * 50, 1e3);
8604
9298
  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
9299
  console.log("[Pipeline] Raw vectorDB.query response:", {
8606
9300
  rawCount: rawSources.length,
@@ -8624,40 +9318,29 @@ ${m.content}`).join("\n\n---\n\n");
8624
9318
  var _a3;
8625
9319
  return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= scoreThreshold;
8626
9320
  });
8627
- const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
9321
+ const rerankLimit = Math.max(retrievalLimit, fullSources.length);
8628
9322
  const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
8629
9323
  if (!hasNumericPredicates && useReranking) {
8630
9324
  fullSources = (yield new __await(this.reranker.rerank(fullSources, question, rerankLimit))).filter((s) => Boolean(s && typeof s === "object"));
8631
- } else if (!wantsExhaustiveList) {
8632
- fullSources = fullSources.slice(0, topK);
8633
9325
  }
8634
9326
  const rerankMs = performance.now() - rerankStart;
8635
- let context = fullSources.length ? fullSources.map((m, i) => {
9327
+ const totalCount = fullSources.length;
9328
+ const promptSources = fullSources.slice(0, 15);
9329
+ let context = promptSources.length ? `[SEARCH SUMMARY: Found ${totalCount} matching record(s) out of ${rawSources.length} total resources searched in database. Context includes top ${promptSources.length} relevant records]
9330
+
9331
+ ` + promptSources.map((m, i) => {
8636
9332
  var _a3;
8637
9333
  return `[Source ${i + 1}]
8638
9334
  ${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
8639
9335
  }).join("\n\n---\n\n") : "No relevant context found.";
8640
- let displayCount = 15;
8641
- if (hasMetadataFilter) {
8642
- displayCount = fullSources.length;
8643
- } else {
8644
- const baseThreshold = Math.max(scoreThreshold, 0.4);
8645
- const highlyRelevant = fullSources.filter((m) => {
8646
- var _a3;
8647
- return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= baseThreshold;
8648
- });
8649
- displayCount = Math.max(highlyRelevant.length, topK);
8650
- if (displayCount > 15) {
8651
- displayCount = 15;
8652
- }
8653
- }
8654
9336
  const sources = [...fullSources].filter((s) => Boolean(s && typeof s === "object")).sort((a, b) => {
8655
9337
  var _a3, _b2;
8656
9338
  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);
9339
+ });
8658
9340
  console.log("[Pipeline] Final sources for prompt & UI:", {
8659
9341
  count: sources.length,
8660
- sources: sources.map((s, idx) => {
9342
+ totalRawCount: rawSources.length,
9343
+ sources: sources.slice(0, 10).map((s, idx) => {
8661
9344
  var _a3;
8662
9345
  return {
8663
9346
  rank: idx + 1,
@@ -8857,7 +9540,7 @@ ${context}`;
8857
9540
  }
8858
9541
  yield fullReply;
8859
9542
  }
8860
- const runHallucination = ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) === true || this.config.llm.provider !== "ollama" && ((_x = this.config.llm.options) == null ? void 0 : _x.hallucinationScoring) !== false;
9543
+ const runHallucination = ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) === true;
8861
9544
  if (runHallucination) {
8862
9545
  hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
8863
9546
  }
@@ -8866,7 +9549,7 @@ ${context}`;
8866
9549
  const latency = {
8867
9550
  embedMs: Math.round(embedMs),
8868
9551
  retrieveMs: Math.round(retrieveMs),
8869
- rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_y = this.config.rag) == null ? void 0 : _y.useReranking)) ? Math.round(rerankMs) : void 0,
9552
+ rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_x = this.config.rag) == null ? void 0 : _x.useReranking)) ? Math.round(rerankMs) : void 0,
8870
9553
  generateMs: Math.round(generateMs),
8871
9554
  totalMs: Math.round(totalMs)
8872
9555
  };
@@ -8879,7 +9562,7 @@ ${context}`;
8879
9562
  totalTokens: promptTokens + completionTokens,
8880
9563
  estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
8881
9564
  };
8882
- const awaitHallucination = ((_z = this.config.llm.options) == null ? void 0 : _z.awaitHallucination) === true;
9565
+ const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
8883
9566
  const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
8884
9567
  uiTransformationPromise,
8885
9568
  awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
@@ -8908,10 +9591,10 @@ ${context}`;
8908
9591
  hallucinationReason: hScore.reason
8909
9592
  } : {});
8910
9593
  const trace = buildTrace(hallucinationResult);
8911
- const isTelemetryActive = (_B = (_A = this.config.telemetry) == null ? void 0 : _A.enabled) != null ? _B : Boolean(this.config.licenseKey);
9594
+ const isTelemetryActive = (_A = (_z = this.config.telemetry) == null ? void 0 : _z.enabled) != null ? _A : Boolean(this.config.licenseKey);
8912
9595
  if (isTelemetryActive) {
8913
9596
  const defaultUrl = process.env.NODE_ENV === "development" && !process.env.TELEMETRY_URL && !process.env.NEXT_PUBLIC_TELEMETRY_URL ? "http://localhost:3001/api/telemetry" : "https://retrivora.com/api/telemetry";
8914
- const telemetryUrl = ((_C = this.config.telemetry) == null ? void 0 : _C.url) || process.env.TELEMETRY_URL || process.env.NEXT_PUBLIC_TELEMETRY_URL || defaultUrl;
9597
+ const telemetryUrl = ((_B = this.config.telemetry) == null ? void 0 : _B.url) || process.env.TELEMETRY_URL || process.env.NEXT_PUBLIC_TELEMETRY_URL || defaultUrl;
8915
9598
  const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
8916
9599
  (async () => {
8917
9600
  try {
@@ -8970,9 +9653,8 @@ ${context}`;
8970
9653
  { visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
8971
9654
  );
8972
9655
  }
8973
- const isLocalProvider = this.config.llm.provider === "ollama";
8974
- const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
8975
- if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
9656
+ const enableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.enableLlmUiTransform) === true;
9657
+ if (forceDeterministic || !enableLlmUiTransform) {
8976
9658
  return UITransformer.transform(question, sources, this.config, cachedSchema);
8977
9659
  }
8978
9660
  try {
@@ -9129,7 +9811,10 @@ ${context}`;
9129
9811
  Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.
9130
9812
 
9131
9813
  History:
9132
- ${history.map((m) => `${m.role}: ${m.content}`).join("\n")}
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")}
9133
9818
 
9134
9819
  New Question: ${question}
9135
9820
 
@@ -9153,8 +9838,11 @@ Optimized Search Query:`;
9153
9838
  const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
9154
9839
  try {
9155
9840
  const { sources } = await this.retrieve(query, { namespace: ns, topK: 5 });
9156
- if (sources.length === 0) return [];
9157
- const context = sources.map((s) => s.content).join("\n\n---\n\n");
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");
9158
9846
  const prompt = `Based on the following snippets from a document, what are at least 5 short, relevant questions a user might ask?
9159
9847
  Focus on questions that can be answered by the context.
9160
9848
  Keep each question under 10 words and make them very specific to the content.