@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.mjs CHANGED
@@ -106,6 +106,617 @@ var init_templateUtils = __esm({
106
106
  }
107
107
  });
108
108
 
109
+ // ../../services/llm-gateway/providers/groq.ts
110
+ async function handleGroqRequest(req, apiKeyOverride) {
111
+ const apiKey = apiKeyOverride || process.env.GROQ_API_KEY;
112
+ if (!apiKey) {
113
+ throw new Error("Groq API Key missing. Please set GROQ_API_KEY in environment variables.");
114
+ }
115
+ const modelName = req.model.replace(/^groq\//i, "");
116
+ const payload = __spreadProps(__spreadValues({}, req), {
117
+ model: modelName
118
+ });
119
+ const response = await fetch("https://api.groq.com/openai/v1/chat/completions", {
120
+ method: "POST",
121
+ headers: {
122
+ "Content-Type": "application/json",
123
+ "Authorization": `Bearer ${apiKey}`
124
+ },
125
+ body: JSON.stringify(payload)
126
+ });
127
+ if (!response.ok) {
128
+ const errorText = await response.text();
129
+ throw new Error(`Groq API Error (${response.status}): ${errorText}`);
130
+ }
131
+ if (req.stream && response.body) {
132
+ return { stream: response.body };
133
+ }
134
+ const json = await response.json();
135
+ return { response: json };
136
+ }
137
+ var init_groq = __esm({
138
+ "../../services/llm-gateway/providers/groq.ts"() {
139
+ "use strict";
140
+ }
141
+ });
142
+
143
+ // ../../services/llm-gateway/providers/openai.ts
144
+ async function handleOpenAIRequest(req, apiKeyOverride) {
145
+ const apiKey = apiKeyOverride || process.env.OPENAI_API_KEY;
146
+ if (!apiKey) {
147
+ throw new Error("OpenAI API Key missing. Please set OPENAI_API_KEY in environment variables.");
148
+ }
149
+ const modelName = req.model.replace(/^(openai|gpt)\//i, "");
150
+ const payload = __spreadProps(__spreadValues({}, req), {
151
+ model: modelName
152
+ });
153
+ const response = await fetch("https://api.openai.com/v1/chat/completions", {
154
+ method: "POST",
155
+ headers: {
156
+ "Content-Type": "application/json",
157
+ "Authorization": `Bearer ${apiKey}`
158
+ },
159
+ body: JSON.stringify(payload)
160
+ });
161
+ if (!response.ok) {
162
+ const errorText = await response.text();
163
+ throw new Error(`OpenAI API Error (${response.status}): ${errorText}`);
164
+ }
165
+ if (req.stream && response.body) {
166
+ return { stream: response.body };
167
+ }
168
+ const json = await response.json();
169
+ return { response: json };
170
+ }
171
+ async function handleOpenAIEmbedding(req, apiKeyOverride) {
172
+ const apiKey = apiKeyOverride || process.env.OPENAI_API_KEY;
173
+ if (!apiKey) {
174
+ throw new Error("OpenAI API Key missing. Please set OPENAI_API_KEY in environment variables.");
175
+ }
176
+ const modelName = req.model.replace(/^(openai)\//i, "");
177
+ const response = await fetch("https://api.openai.com/v1/embeddings", {
178
+ method: "POST",
179
+ headers: {
180
+ "Content-Type": "application/json",
181
+ "Authorization": `Bearer ${apiKey}`
182
+ },
183
+ body: JSON.stringify({
184
+ model: modelName,
185
+ input: req.input
186
+ })
187
+ });
188
+ if (!response.ok) {
189
+ const errorText = await response.text();
190
+ throw new Error(`OpenAI Embedding API Error (${response.status}): ${errorText}`);
191
+ }
192
+ return await response.json();
193
+ }
194
+ var init_openai = __esm({
195
+ "../../services/llm-gateway/providers/openai.ts"() {
196
+ "use strict";
197
+ }
198
+ });
199
+
200
+ // ../../services/llm-gateway/providers/gemini.ts
201
+ async function handleGeminiRequest(req, apiKeyOverride) {
202
+ const apiKey = apiKeyOverride || process.env.GEMINI_API_KEY;
203
+ if (!apiKey) {
204
+ throw new Error("Gemini API Key missing. Please set GEMINI_API_KEY in environment variables.");
205
+ }
206
+ let modelName = req.model.replace(/^(google|gemini)\//i, "");
207
+ if (!modelName.startsWith("gemini-")) {
208
+ modelName = `gemini-${modelName}`;
209
+ }
210
+ const payload = __spreadProps(__spreadValues({}, req), {
211
+ model: modelName
212
+ });
213
+ const response = await fetch("https://generativelanguage.googleapis.com/v1beta/openai/chat/completions", {
214
+ method: "POST",
215
+ headers: {
216
+ "Content-Type": "application/json",
217
+ "Authorization": `Bearer ${apiKey}`
218
+ },
219
+ body: JSON.stringify(payload)
220
+ });
221
+ if (!response.ok) {
222
+ const errorText = await response.text();
223
+ throw new Error(`Google Gemini API Error (${response.status}): ${errorText}`);
224
+ }
225
+ if (req.stream && response.body) {
226
+ return { stream: response.body };
227
+ }
228
+ const json = await response.json();
229
+ return { response: json };
230
+ }
231
+ async function handleGeminiEmbedding(req, apiKeyOverride) {
232
+ const apiKey = apiKeyOverride || process.env.GEMINI_API_KEY;
233
+ if (!apiKey) {
234
+ throw new Error("Gemini API Key missing. Please set GEMINI_API_KEY in environment variables.");
235
+ }
236
+ let modelName = req.model.replace(/^(google|gemini)\//i, "");
237
+ if (!modelName || modelName === "default" || modelName.includes("text-embedding-3") || modelName.includes("ada") || !modelName.startsWith("text-embedding-00") && !modelName.startsWith("embedding-00")) {
238
+ modelName = "text-embedding-004";
239
+ }
240
+ const response = await fetch("https://generativelanguage.googleapis.com/v1beta/openai/embeddings", {
241
+ method: "POST",
242
+ headers: {
243
+ "Content-Type": "application/json",
244
+ "Authorization": `Bearer ${apiKey}`
245
+ },
246
+ body: JSON.stringify({
247
+ model: modelName,
248
+ input: req.input
249
+ })
250
+ });
251
+ if (!response.ok) {
252
+ const errorText = await response.text();
253
+ throw new Error(`Google Gemini Embedding API Error (${response.status}): ${errorText}`);
254
+ }
255
+ return await response.json();
256
+ }
257
+ var init_gemini = __esm({
258
+ "../../services/llm-gateway/providers/gemini.ts"() {
259
+ "use strict";
260
+ }
261
+ });
262
+
263
+ // ../../services/llm-gateway/providers/huggingface.ts
264
+ async function handleHuggingFaceChatRequest(req, apiKeyOverride) {
265
+ var _a2, _b;
266
+ const apiKey = apiKeyOverride || process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN;
267
+ if (!apiKey) {
268
+ throw new Error("HuggingFace API Key missing. Set HUGGINGFACE_API_KEY or HF_TOKEN in environment variables.");
269
+ }
270
+ let modelName = req.model.replace(/^(huggingface|hf)\//i, "");
271
+ if (!modelName || modelName === "default" || modelName.toLowerCase() === "qwen" || modelName.toLowerCase() === "qwen-coder") {
272
+ modelName = "Qwen/Qwen2.5-Coder-32B-Instruct";
273
+ }
274
+ const payload = __spreadProps(__spreadValues({}, req), {
275
+ model: modelName
276
+ });
277
+ try {
278
+ const response = await fetch("https://router.huggingface.co/v1/chat/completions", {
279
+ method: "POST",
280
+ headers: {
281
+ "Content-Type": "application/json",
282
+ "Authorization": `Bearer ${apiKey}`
283
+ },
284
+ body: JSON.stringify(payload)
285
+ });
286
+ if (response.ok) {
287
+ if (req.stream && response.body) {
288
+ return { stream: response.body };
289
+ }
290
+ const json = await response.json();
291
+ return { response: json };
292
+ }
293
+ } catch (e) {
294
+ }
295
+ try {
296
+ const response = await fetch("https://router.huggingface.co/hf-inference/v1/chat/completions", {
297
+ method: "POST",
298
+ headers: {
299
+ "Content-Type": "application/json",
300
+ "Authorization": `Bearer ${apiKey}`
301
+ },
302
+ body: JSON.stringify(payload)
303
+ });
304
+ if (response.ok) {
305
+ if (req.stream && response.body) {
306
+ return { stream: response.body };
307
+ }
308
+ const json = await response.json();
309
+ return { response: json };
310
+ }
311
+ } catch (e) {
312
+ }
313
+ const lastUserMsg = ((_a2 = req.messages.filter((m) => m.role === "user").pop()) == null ? void 0 : _a2.content) || "Hello";
314
+ const pipelineRes = await fetch(`https://router.huggingface.co/hf-inference/models/${modelName}`, {
315
+ method: "POST",
316
+ headers: {
317
+ "Content-Type": "application/json",
318
+ "Authorization": `Bearer ${apiKey}`
319
+ },
320
+ body: JSON.stringify({
321
+ inputs: lastUserMsg,
322
+ parameters: { max_new_tokens: req.max_tokens || 256, temperature: req.temperature || 0.7 },
323
+ options: { wait_for_model: true }
324
+ })
325
+ });
326
+ if (!pipelineRes.ok) {
327
+ const errorText = await pipelineRes.text();
328
+ throw new Error(`HuggingFace API Error (${pipelineRes.status}): ${errorText}`);
329
+ }
330
+ const raw = await pipelineRes.json();
331
+ const textOutput = Array.isArray(raw) ? ((_b = raw[0]) == null ? void 0 : _b.generated_text) || JSON.stringify(raw) : JSON.stringify(raw);
332
+ const formattedResponse = {
333
+ id: `hf-${Date.now()}`,
334
+ object: "chat.completion",
335
+ created: Math.floor(Date.now() / 1e3),
336
+ model: modelName,
337
+ choices: [
338
+ {
339
+ index: 0,
340
+ message: {
341
+ role: "assistant",
342
+ content: textOutput
343
+ },
344
+ finish_reason: "stop"
345
+ }
346
+ ],
347
+ usage: {
348
+ prompt_tokens: lastUserMsg.length,
349
+ completion_tokens: textOutput.length,
350
+ total_tokens: lastUserMsg.length + textOutput.length
351
+ }
352
+ };
353
+ return { response: formattedResponse };
354
+ }
355
+ async function handleHuggingFaceEmbedding(req, apiKeyOverride) {
356
+ const apiKey = apiKeyOverride || process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN;
357
+ if (!apiKey) {
358
+ throw new Error("HuggingFace API Key missing. Set HUGGINGFACE_API_KEY or HF_TOKEN in environment variables.");
359
+ }
360
+ let modelName = req.model.replace(/^(huggingface|hf)\//i, "");
361
+ if (!modelName || modelName === "default" || modelName.includes("text-embedding-3") || modelName.includes("ada") || !modelName.includes("/") && !modelName.includes("bge") && !modelName.includes("sentence-transformers")) {
362
+ modelName = "BAAI/bge-base-en-v1.5";
363
+ }
364
+ const inputs = Array.isArray(req.input) ? req.input : [req.input];
365
+ const fetchEmbeddingFromModel = async (targetModel) => {
366
+ try {
367
+ const routerRes = await fetch("https://router.huggingface.co/hf-inference/v1/embeddings", {
368
+ method: "POST",
369
+ headers: {
370
+ "Content-Type": "application/json",
371
+ "Authorization": `Bearer ${apiKey}`
372
+ },
373
+ body: JSON.stringify({
374
+ model: targetModel,
375
+ input: inputs
376
+ })
377
+ });
378
+ if (routerRes.ok) {
379
+ const json = await routerRes.json();
380
+ if (json && json.data) return json;
381
+ }
382
+ } catch (e) {
383
+ }
384
+ const response = await fetch(`https://router.huggingface.co/hf-inference/models/${targetModel}`, {
385
+ method: "POST",
386
+ headers: {
387
+ "Content-Type": "application/json",
388
+ "Authorization": `Bearer ${apiKey}`
389
+ },
390
+ body: JSON.stringify({
391
+ inputs,
392
+ options: { wait_for_model: true }
393
+ })
394
+ });
395
+ if (!response.ok) {
396
+ const errorText = await response.text();
397
+ throw new Error(`HuggingFace API Error (${response.status}): ${errorText}`);
398
+ }
399
+ const rawData = await response.json();
400
+ const embeddings = Array.isArray(rawData[0]) ? typeof rawData[0][0] === "number" ? rawData : rawData.map((arr) => arr[0]) : [rawData];
401
+ return {
402
+ object: "list",
403
+ data: embeddings.map((vec, idx) => ({
404
+ object: "embedding",
405
+ embedding: vec,
406
+ index: idx
407
+ })),
408
+ model: targetModel,
409
+ usage: {
410
+ prompt_tokens: inputs.reduce((acc, str) => acc + str.length, 0),
411
+ completion_tokens: 0,
412
+ total_tokens: inputs.reduce((acc, str) => acc + str.length, 0)
413
+ }
414
+ };
415
+ };
416
+ try {
417
+ return await fetchEmbeddingFromModel(modelName);
418
+ } catch (err) {
419
+ if (modelName !== "BAAI/bge-base-en-v1.5") {
420
+ console.warn(`[LLM Gateway] HuggingFace model ${modelName} failed. Falling back to BAAI/bge-base-en-v1.5...`, err);
421
+ return await fetchEmbeddingFromModel("BAAI/bge-base-en-v1.5");
422
+ }
423
+ throw err;
424
+ }
425
+ }
426
+ var init_huggingface = __esm({
427
+ "../../services/llm-gateway/providers/huggingface.ts"() {
428
+ "use strict";
429
+ }
430
+ });
431
+
432
+ // ../../services/llm-gateway/providers/anthropic.ts
433
+ async function handleAnthropicRequest(req, apiKeyOverride) {
434
+ var _a2, _b;
435
+ const apiKey = apiKeyOverride || process.env.ANTHROPIC_API_KEY;
436
+ if (!apiKey) {
437
+ throw new Error("Anthropic API Key missing. Please set ANTHROPIC_API_KEY in environment variables.");
438
+ }
439
+ const modelName = req.model.replace(/^(anthropic|claude)\//i, "");
440
+ let systemPrompt = void 0;
441
+ const anthropicMessages = [];
442
+ for (const msg of req.messages) {
443
+ if (msg.role === "system") {
444
+ systemPrompt = systemPrompt ? `${systemPrompt}
445
+ ${msg.content}` : msg.content;
446
+ } else {
447
+ anthropicMessages.push({
448
+ role: msg.role === "assistant" ? "assistant" : "user",
449
+ content: msg.content
450
+ });
451
+ }
452
+ }
453
+ if (anthropicMessages.length === 0) {
454
+ anthropicMessages.push({ role: "user", content: "Hello" });
455
+ }
456
+ const payload = {
457
+ model: modelName,
458
+ messages: anthropicMessages,
459
+ max_tokens: req.max_tokens || req.max_completion_tokens || 1024,
460
+ stream: req.stream || false
461
+ };
462
+ if (systemPrompt) {
463
+ payload.system = systemPrompt;
464
+ }
465
+ if (req.temperature !== void 0) {
466
+ payload.temperature = req.temperature;
467
+ }
468
+ const response = await fetch("https://api.anthropic.com/v1/messages", {
469
+ method: "POST",
470
+ headers: {
471
+ "Content-Type": "application/json",
472
+ "x-api-key": apiKey,
473
+ "anthropic-version": "2023-06-01"
474
+ },
475
+ body: JSON.stringify(payload)
476
+ });
477
+ if (!response.ok) {
478
+ const errorText = await response.text();
479
+ throw new Error(`Anthropic API Error (${response.status}): ${errorText}`);
480
+ }
481
+ if (req.stream && response.body) {
482
+ return { stream: response.body };
483
+ }
484
+ const json = await response.json();
485
+ const textContent = ((_b = (_a2 = json.content) == null ? void 0 : _a2[0]) == null ? void 0 : _b.text) || "";
486
+ const openAIResponse = {
487
+ id: json.id || `chatcmpl-${Date.now()}`,
488
+ object: "chat.completion",
489
+ created: Math.floor(Date.now() / 1e3),
490
+ model: json.model || modelName,
491
+ choices: [
492
+ {
493
+ index: 0,
494
+ message: {
495
+ role: "assistant",
496
+ content: textContent
497
+ },
498
+ finish_reason: json.stop_reason === "end_turn" ? "stop" : json.stop_reason || "stop"
499
+ }
500
+ ],
501
+ usage: json.usage ? {
502
+ prompt_tokens: json.usage.input_tokens,
503
+ completion_tokens: json.usage.output_tokens,
504
+ total_tokens: json.usage.input_tokens + json.usage.output_tokens
505
+ } : void 0
506
+ };
507
+ return { response: openAIResponse };
508
+ }
509
+ var init_anthropic = __esm({
510
+ "../../services/llm-gateway/providers/anthropic.ts"() {
511
+ "use strict";
512
+ }
513
+ });
514
+
515
+ // ../../services/llm-gateway/providers/ollama.ts
516
+ async function handleOllamaRequest(req, baseUrlOverride) {
517
+ const baseUrl = (baseUrlOverride || process.env.OLLAMA_BASE_URL || "http://localhost:11434/v1").replace(/\/+$/, "");
518
+ const modelName = req.model.replace(/^ollama\//i, "");
519
+ const payload = __spreadProps(__spreadValues({}, req), {
520
+ model: modelName
521
+ });
522
+ const response = await fetch(`${baseUrl}/chat/completions`, {
523
+ method: "POST",
524
+ headers: {
525
+ "Content-Type": "application/json"
526
+ },
527
+ body: JSON.stringify(payload)
528
+ });
529
+ if (!response.ok) {
530
+ const errorText = await response.text();
531
+ throw new Error(`Ollama API Error (${response.status}): ${errorText}`);
532
+ }
533
+ if (req.stream && response.body) {
534
+ return { stream: response.body };
535
+ }
536
+ const json = await response.json();
537
+ return { response: json };
538
+ }
539
+ var init_ollama = __esm({
540
+ "../../services/llm-gateway/providers/ollama.ts"() {
541
+ "use strict";
542
+ }
543
+ });
544
+
545
+ // ../../services/llm-gateway/router.ts
546
+ var router_exports = {};
547
+ __export(router_exports, {
548
+ SUPPORTED_MODELS: () => SUPPORTED_MODELS,
549
+ dispatchChatCompletion: () => dispatchChatCompletion,
550
+ dispatchEmbedding: () => dispatchEmbedding,
551
+ resolveProvider: () => resolveProvider
552
+ });
553
+ function resolveProvider(model) {
554
+ const lower = model.toLowerCase();
555
+ if (lower.startsWith("huggingface/") || lower.startsWith("hf/")) {
556
+ return "huggingface";
557
+ }
558
+ if (lower.startsWith("ollama/")) {
559
+ return "ollama";
560
+ }
561
+ if (lower.startsWith("groq/") || lower.includes("llama") || lower.includes("qwen") || lower.includes("mixtral")) {
562
+ return "groq";
563
+ }
564
+ if (process.env.GROQ_API_KEY) return "groq";
565
+ if (process.env.OPENAI_API_KEY) return "openai";
566
+ if (process.env.GEMINI_API_KEY) return "gemini";
567
+ if (process.env.ANTHROPIC_API_KEY) return "anthropic";
568
+ if (process.env.HF_TOKEN || process.env.HUGGINGFACE_API_KEY) return "huggingface";
569
+ return "groq";
570
+ }
571
+ function cleanApiKeyOverride(apiKeyOverride) {
572
+ if (!apiKeyOverride) return void 0;
573
+ const key = apiKeyOverride.trim();
574
+ 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-")) {
575
+ return void 0;
576
+ }
577
+ return key;
578
+ }
579
+ async function dispatchChatCompletion(req, apiKeyOverride) {
580
+ const effectiveKey = cleanApiKeyOverride(apiKeyOverride);
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)}`);
583
+ try {
584
+ switch (provider) {
585
+ case "groq":
586
+ return await handleGroqRequest(req, effectiveKey);
587
+ case "openai":
588
+ return await handleOpenAIRequest(req, effectiveKey);
589
+ case "gemini":
590
+ return await handleGeminiRequest(req, effectiveKey);
591
+ case "anthropic":
592
+ return await handleAnthropicRequest(req, effectiveKey);
593
+ case "ollama":
594
+ return await handleOllamaRequest(req);
595
+ case "huggingface":
596
+ return await handleHuggingFaceChatRequest(req, effectiveKey);
597
+ default:
598
+ throw new Error(`Unsupported LLM provider for model: ${req.model}`);
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
+ });
605
+ if (/rate[- ]?limit|429|exhausted/i.test(error.message)) {
606
+ const isGroqKey = process.env.GROQ_API_KEY || effectiveKey && effectiveKey.startsWith("gsk_");
607
+ const reqModelLower = req.model.toLowerCase();
608
+ if (isGroqKey && !reqModelLower.includes("llama-3.3-70b")) {
609
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to secondary Groq model (llama-3.3-70b-versatile)...`);
610
+ try {
611
+ return await handleGroqRequest(__spreadProps(__spreadValues({}, req), { model: "llama-3.3-70b-versatile" }), effectiveKey);
612
+ } catch (fErr) {
613
+ console.error("[LLM Gateway] Fallback groq/llama-3.3-70b-versatile failed:", fErr.message);
614
+ }
615
+ }
616
+ const geminiKey = process.env.GEMINI_API_KEY || effectiveKey;
617
+ if (provider !== "gemini" && geminiKey && (geminiKey.startsWith("AIza") || !geminiKey.startsWith("AQ."))) {
618
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Google Gemini (gemini-2.5-flash)...`);
619
+ try {
620
+ return await handleGeminiRequest(__spreadProps(__spreadValues({}, req), { model: "gemini-2.5-flash" }), effectiveKey);
621
+ } catch (fErr) {
622
+ console.error("[LLM Gateway] Fallback gemini-2.5-flash failed:", fErr.message);
623
+ }
624
+ }
625
+ if (provider !== "huggingface" && (process.env.HF_TOKEN || process.env.HUGGINGFACE_API_KEY)) {
626
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to Hugging Face (Qwen/Qwen2.5-Coder-32B-Instruct)...`);
627
+ try {
628
+ return await handleHuggingFaceChatRequest(__spreadProps(__spreadValues({}, req), { model: "Qwen/Qwen2.5-Coder-32B-Instruct" }), effectiveKey);
629
+ } catch (fErr) {
630
+ console.error("[LLM Gateway] Fallback HuggingFace Qwen failed:", fErr.message);
631
+ }
632
+ }
633
+ if (provider !== "openai" && process.env.OPENAI_API_KEY) {
634
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to OpenAI (gpt-4o-mini)...`);
635
+ try {
636
+ return await handleOpenAIRequest(__spreadProps(__spreadValues({}, req), { model: "gpt-4o-mini" }), effectiveKey);
637
+ } catch (e) {
638
+ }
639
+ }
640
+ console.warn(`[LLM Gateway] Provider ${provider} rate limited (${error.message}). Falling back to local Ollama (llama3.2)...`);
641
+ return handleOllamaRequest(__spreadProps(__spreadValues({}, req), { model: "llama3.2" }));
642
+ }
643
+ throw error;
644
+ }
645
+ }
646
+ async function dispatchEmbedding(req, apiKeyOverride) {
647
+ const effectiveKey = cleanApiKeyOverride(apiKeyOverride);
648
+ if (req.model.startsWith("hf/") || req.model.startsWith("huggingface/") || req.model.includes("bge-")) {
649
+ try {
650
+ return await handleHuggingFaceEmbedding(req, effectiveKey);
651
+ } catch (err) {
652
+ console.warn("[LLM Gateway] HuggingFace explicit model embedding failed, falling back to default gateway chain:", err);
653
+ }
654
+ }
655
+ const geminiKey = process.env.GEMINI_API_KEY || effectiveKey;
656
+ const isGeminiKeyValid = Boolean(geminiKey && (geminiKey.startsWith("AIza") || !geminiKey.startsWith("AQ.")));
657
+ if (isGeminiKeyValid) {
658
+ try {
659
+ return await handleGeminiEmbedding(req, effectiveKey);
660
+ } catch (err) {
661
+ console.warn("[LLM Gateway] Gemini embedding failed:", err);
662
+ }
663
+ }
664
+ if (process.env.OPENAI_API_KEY) {
665
+ try {
666
+ return await handleOpenAIEmbedding(req, effectiveKey);
667
+ } catch (err) {
668
+ console.warn("[LLM Gateway] OpenAI embedding failed:", err);
669
+ }
670
+ }
671
+ if (process.env.HUGGINGFACE_API_KEY || process.env.HF_TOKEN) {
672
+ try {
673
+ return await handleHuggingFaceEmbedding(req, effectiveKey);
674
+ } catch (err) {
675
+ console.warn("[LLM Gateway] HuggingFace fallback embedding failed:", err);
676
+ }
677
+ }
678
+ return handleGeminiEmbedding(req, effectiveKey);
679
+ }
680
+ var SUPPORTED_MODELS;
681
+ var init_router = __esm({
682
+ "../../services/llm-gateway/router.ts"() {
683
+ "use strict";
684
+ init_groq();
685
+ init_openai();
686
+ init_gemini();
687
+ init_huggingface();
688
+ init_anthropic();
689
+ init_ollama();
690
+ SUPPORTED_MODELS = [
691
+ { id: "groq/llama-3.1-8b-instant", object: "model", created: 17e8, owned_by: "groq" },
692
+ { id: "llama-3.1-8b-instant", object: "model", created: 17e8, owned_by: "groq" },
693
+ { id: "groq/llama-3.3-70b-versatile", object: "model", created: 17e8, owned_by: "groq" },
694
+ { id: "llama-3.3-70b-versatile", object: "model", created: 17e8, owned_by: "groq" },
695
+ { id: "gpt-4o-mini", object: "model", created: 17e8, owned_by: "openai" },
696
+ { id: "openai/gpt-4o-mini", object: "model", created: 17e8, owned_by: "openai" },
697
+ { id: "gpt-4o", object: "model", created: 17e8, owned_by: "openai" },
698
+ { id: "gemini-2.5-flash", object: "model", created: 17e8, owned_by: "google" },
699
+ { id: "google/gemini-2.5-flash", object: "model", created: 17e8, owned_by: "google" },
700
+ { id: "claude-3-5-haiku-20241022", object: "model", created: 17e8, owned_by: "anthropic" },
701
+ { id: "anthropic/claude-3-5-haiku-20241022", object: "model", created: 17e8, owned_by: "anthropic" },
702
+ { id: "text-embedding-004", object: "model", created: 17e8, owned_by: "google" },
703
+ { id: "google/text-embedding-004", object: "model", created: 17e8, owned_by: "google" },
704
+ { id: "BAAI/bge-base-en-v1.5", object: "model", created: 17e8, owned_by: "huggingface" },
705
+ { id: "huggingface/BAAI/bge-base-en-v1.5", object: "model", created: 17e8, owned_by: "huggingface" },
706
+ { id: "groq/qwen3-32b", object: "model", created: 17e8, owned_by: "groq" },
707
+ { id: "qwen/qwen3-32b", object: "model", created: 17e8, owned_by: "groq" },
708
+ { id: "qwen/qwen3-embedding-8b", object: "model", created: 17e8, owned_by: "qwen" },
709
+ { id: "qwen3-embedding-8b", object: "model", created: 17e8, owned_by: "qwen" },
710
+ { id: "ollama/llama3.2", object: "model", created: 17e8, owned_by: "ollama" }
711
+ ];
712
+ if (typeof globalThis !== "undefined") {
713
+ const _g2 = globalThis;
714
+ _g2.__retrivoraDispatchChat = dispatchChatCompletion;
715
+ _g2.__retrivoraDispatchEmbedding = dispatchEmbedding;
716
+ }
717
+ }
718
+ });
719
+
109
720
  // src/providers/vectordb/BaseVectorProvider.ts
110
721
  var BaseVectorProvider;
111
722
  var init_BaseVectorProvider = __esm({
@@ -2790,12 +3401,13 @@ var OpenAIProvider = class {
2790
3401
  role: "system",
2791
3402
  content: buildSystemContent(basePrompt, context)
2792
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
+ }));
2793
3408
  const formattedMessages = [
2794
3409
  systemMessage,
2795
- ...messages.map((m) => ({
2796
- role: m.role,
2797
- content: m.content
2798
- }))
3410
+ ...safeMessages
2799
3411
  ];
2800
3412
  const completion = await this.client.chat.completions.create({
2801
3413
  model: this.llmConfig.model,
@@ -2814,12 +3426,13 @@ var OpenAIProvider = class {
2814
3426
  role: "system",
2815
3427
  content: buildSystemContent(basePrompt, context)
2816
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
+ }));
2817
3433
  const formattedMessages = [
2818
3434
  systemMessage,
2819
- ...messages.map((m) => ({
2820
- role: m.role,
2821
- content: m.content
2822
- }))
3435
+ ...safeStreamMessages
2823
3436
  ];
2824
3437
  const stream = yield new __await(this.client.chat.completions.create({
2825
3438
  model: this.llmConfig.model,
@@ -3350,9 +3963,9 @@ var GeminiProvider = class {
3350
3963
  * - Messages must strictly alternate between `user` and `model`.
3351
3964
  */
3352
3965
  buildGeminiContents(messages) {
3353
- return messages.filter((m) => m.role !== "system").map((m) => ({
3966
+ return (messages || []).filter((m) => Boolean(m && typeof m === "object" && m.role !== "system")).map((m) => ({
3354
3967
  role: m.role === "assistant" ? "model" : "user",
3355
- parts: [{ text: m.content }]
3968
+ parts: [{ text: typeof m.content === "string" ? m.content : m.content != null ? String(m.content) : "" }]
3356
3969
  }));
3357
3970
  }
3358
3971
  // -------------------------------------------------------------------------
@@ -3555,12 +4168,13 @@ var GroqProvider = class {
3555
4168
  role: "system",
3556
4169
  content: buildSystemContent(basePrompt, context)
3557
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
+ }));
3558
4175
  const formattedMessages = [
3559
4176
  systemMessage,
3560
- ...messages.map((m) => ({
3561
- role: m.role,
3562
- content: m.content
3563
- }))
4177
+ ...safeMessages
3564
4178
  ];
3565
4179
  const completion = await this.client.chat.completions.create({
3566
4180
  model: this.llmConfig.model,
@@ -3579,12 +4193,13 @@ var GroqProvider = class {
3579
4193
  role: "system",
3580
4194
  content: buildSystemContent(basePrompt, context)
3581
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
+ }));
3582
4200
  const formattedMessages = [
3583
4201
  systemMessage,
3584
- ...messages.map((m) => ({
3585
- role: m.role,
3586
- content: m.content
3587
- }))
4202
+ ...safeStreamMessages
3588
4203
  ];
3589
4204
  const stream = yield new __await(this.client.chat.completions.create({
3590
4205
  model: this.llmConfig.model,
@@ -3713,12 +4328,13 @@ var QwenProvider = class {
3713
4328
  role: "system",
3714
4329
  content: buildSystemContent(basePrompt, context)
3715
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
+ }));
3716
4335
  const formattedMessages = [
3717
4336
  systemMessage,
3718
- ...messages.map((m) => ({
3719
- role: m.role,
3720
- content: m.content
3721
- }))
4337
+ ...safeMessages
3722
4338
  ];
3723
4339
  const completion = await this.client.chat.completions.create({
3724
4340
  model: this.llmConfig.model,
@@ -3737,12 +4353,13 @@ var QwenProvider = class {
3737
4353
  role: "system",
3738
4354
  content: buildSystemContent(basePrompt, context)
3739
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
+ }));
3740
4360
  const formattedMessages = [
3741
4361
  systemMessage,
3742
- ...messages.map((m) => ({
3743
- role: m.role,
3744
- content: m.content
3745
- }))
4362
+ ...safeStreamMessages
3746
4363
  ];
3747
4364
  const stream = yield new __await(this.client.chat.completions.create({
3748
4365
  model: this.llmConfig.model,
@@ -3880,6 +4497,17 @@ var VECTOR_PROFILES = {
3880
4497
  };
3881
4498
 
3882
4499
  // src/llm/providers/UniversalLLMAdapter.ts
4500
+ function extractContent(obj) {
4501
+ var _a2, _b, _c;
4502
+ if (!obj || typeof obj !== "object") return void 0;
4503
+ const choice = (_a2 = obj.choices) == null ? void 0 : _a2[0];
4504
+ if (!choice) return void 0;
4505
+ if (typeof ((_b = choice.message) == null ? void 0 : _b.content) === "string") return choice.message.content;
4506
+ if (typeof ((_c = choice.delta) == null ? void 0 : _c.content) === "string") return choice.delta.content;
4507
+ if (typeof choice.text === "string") return choice.text;
4508
+ if (typeof choice.content === "string") return choice.content;
4509
+ return void 0;
4510
+ }
3883
4511
  var UniversalLLMAdapter = class {
3884
4512
  constructor(config) {
3885
4513
  var _a2, _b, _c, _d, _e, _f, _g2, _h;
@@ -3911,14 +4539,18 @@ var UniversalLLMAdapter = class {
3911
4539
  });
3912
4540
  }
3913
4541
  async chat(messages, context) {
3914
- var _a2, _b, _c, _d, _e, _f;
4542
+ var _a2, _b, _c;
3915
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
+ }));
3916
4548
  const formattedMessages = [
3917
4549
  { role: "system", content: `${this.systemPrompt}
3918
4550
 
3919
4551
  Context:
3920
4552
  ${context != null ? context : "None"}` },
3921
- ...messages
4553
+ ...safeMessages
3922
4554
  ];
3923
4555
  let payload;
3924
4556
  if (this.opts.chatPayloadTemplate) {
@@ -3939,25 +4571,41 @@ ${context != null ? context : "None"}` },
3939
4571
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
3940
4572
  if (isSelfHost || Boolean(process.env.VERCEL)) {
3941
4573
  const _g2 = globalThis;
3942
- if (typeof _g2.__retrivoraDispatchChat === "function") {
4574
+ let dispatch = _g2.__retrivoraDispatchChat;
4575
+ if (typeof dispatch !== "function") {
3943
4576
  try {
3944
- const res = await _g2.__retrivoraDispatchChat({
4577
+ const gateway = await Promise.resolve().then(() => (init_router(), router_exports));
4578
+ if (gateway == null ? void 0 : gateway.dispatchChatCompletion) {
4579
+ _g2.__retrivoraDispatchChat = gateway.dispatchChatCompletion;
4580
+ _g2.__retrivoraDispatchEmbedding = gateway.dispatchEmbedding;
4581
+ dispatch = gateway.dispatchChatCompletion;
4582
+ }
4583
+ } catch (e) {
4584
+ }
4585
+ }
4586
+ if (typeof dispatch === "function") {
4587
+ try {
4588
+ const res = await dispatch({
3945
4589
  model: this.model,
3946
4590
  messages: formattedMessages,
3947
4591
  max_tokens: this.maxTokens,
3948
4592
  temperature: this.temperature
3949
4593
  }, this.apiKey);
3950
- if ((_e = (_d = (_c = (_b = res == null ? void 0 : res.response) == null ? void 0 : _b.choices) == null ? void 0 : _c[0]) == null ? void 0 : _d.message) == null ? void 0 : _e.content) {
3951
- return res.response.choices[0].message.content;
4594
+ const content = extractContent(res == null ? void 0 : res.response);
4595
+ if (content !== void 0) {
4596
+ return content;
3952
4597
  }
4598
+ throw new Error(`[UniversalLLMAdapter] In-process dispatch returned empty content for model: ${this.model}`);
3953
4599
  } catch (dispatchErr) {
3954
4600
  throw dispatchErr;
3955
4601
  }
4602
+ } else {
4603
+ 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.`);
3956
4604
  }
3957
4605
  }
3958
4606
  const { data } = await this.http.post(path2, payload);
3959
- const extractPath = (_f = this.opts.responseExtractPath) != null ? _f : "choices[0].message.content";
3960
- const result = resolvePath(data, extractPath);
4607
+ const extractPath = (_b = this.opts.responseExtractPath) != null ? _b : "choices[0].message.content";
4608
+ const result = (_c = resolvePath(data, extractPath)) != null ? _c : extractContent(data);
3961
4609
  if (result === void 0) {
3962
4610
  throw new Error(`[UniversalLLMAdapter] Could not extract text from path '${extractPath}' in response.`);
3963
4611
  }
@@ -3970,16 +4618,20 @@ ${context != null ? context : "None"}` },
3970
4618
  */
3971
4619
  chatStream(messages, context) {
3972
4620
  return __asyncGenerator(this, null, function* () {
3973
- var _a2, _b, _c, _d, _e, _f, _g2;
4621
+ var _a2, _b, _c, _d, _e;
3974
4622
  const path2 = (_a2 = this.opts.chatPath) != null ? _a2 : "/chat/completions";
3975
4623
  const url = `${this.baseUrl.replace(/\/$/, "")}${path2}`;
3976
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
+ }));
3977
4629
  const formattedMessages = [
3978
4630
  { role: "system", content: `${this.systemPrompt}
3979
4631
 
3980
4632
  Context:
3981
4633
  ${context != null ? context : "None"}` },
3982
- ...messages
4634
+ ...safeMessages
3983
4635
  ];
3984
4636
  let payload;
3985
4637
  if (this.opts.chatPayloadTemplate) {
@@ -4004,10 +4656,22 @@ ${context != null ? context : "None"}` },
4004
4656
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4005
4657
  let streamBody = null;
4006
4658
  if (isSelfHost || Boolean(process.env.VERCEL)) {
4007
- const _g3 = globalThis;
4008
- if (typeof _g3.__retrivoraDispatchChat === "function") {
4659
+ const _g2 = globalThis;
4660
+ let dispatch = _g2.__retrivoraDispatchChat;
4661
+ if (typeof dispatch !== "function") {
4009
4662
  try {
4010
- const res = yield new __await(_g3.__retrivoraDispatchChat({
4663
+ const gateway = yield new __await(Promise.resolve().then(() => (init_router(), router_exports)));
4664
+ if (gateway == null ? void 0 : gateway.dispatchChatCompletion) {
4665
+ _g2.__retrivoraDispatchChat = gateway.dispatchChatCompletion;
4666
+ _g2.__retrivoraDispatchEmbedding = gateway.dispatchEmbedding;
4667
+ dispatch = gateway.dispatchChatCompletion;
4668
+ }
4669
+ } catch (e) {
4670
+ }
4671
+ }
4672
+ if (typeof dispatch === "function") {
4673
+ try {
4674
+ const res = yield new __await(dispatch({
4011
4675
  model: this.model,
4012
4676
  messages: formattedMessages,
4013
4677
  max_tokens: this.maxTokens,
@@ -4016,13 +4680,19 @@ ${context != null ? context : "None"}` },
4016
4680
  }, this.apiKey));
4017
4681
  if (res == null ? void 0 : res.stream) {
4018
4682
  streamBody = res.stream;
4019
- } 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) {
4020
- yield res.response.choices[0].message.content;
4021
- return;
4683
+ } else {
4684
+ const content = extractContent(res == null ? void 0 : res.response);
4685
+ if (content !== void 0) {
4686
+ yield content;
4687
+ return;
4688
+ }
4689
+ throw new Error(`[UniversalLLMAdapter] In-process dispatch stream returned empty response for model: ${this.model}`);
4022
4690
  }
4023
4691
  } catch (dispatchErr) {
4024
4692
  throw dispatchErr;
4025
4693
  }
4694
+ } else {
4695
+ 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.`);
4026
4696
  }
4027
4697
  }
4028
4698
  if (!streamBody) {
@@ -4049,14 +4719,14 @@ ${context != null ? context : "None"}` },
4049
4719
  if (done) break;
4050
4720
  buffer += decoder.decode(value, { stream: true });
4051
4721
  const lines = buffer.split("\n");
4052
- buffer = (_g2 = lines.pop()) != null ? _g2 : "";
4722
+ buffer = (_c = lines.pop()) != null ? _c : "";
4053
4723
  for (const line of lines) {
4054
4724
  const trimmed = line.trim();
4055
4725
  if (!trimmed || trimmed === "data: [DONE]") continue;
4056
4726
  if (!trimmed.startsWith("data:")) continue;
4057
4727
  try {
4058
4728
  const json = JSON.parse(trimmed.slice(5).trim());
4059
- const text = resolvePath(json, extractPath);
4729
+ const text = (_d = resolvePath(json, extractPath)) != null ? _d : extractContent(json);
4060
4730
  if (text && typeof text === "string") yield text;
4061
4731
  } catch (e) {
4062
4732
  }
@@ -4066,7 +4736,7 @@ ${context != null ? context : "None"}` },
4066
4736
  const jsonStr = buffer.replace(/^data:\s*/, "").trim();
4067
4737
  try {
4068
4738
  const json = JSON.parse(jsonStr);
4069
- const text = resolvePath(json, extractPath);
4739
+ const text = (_e = resolvePath(json, extractPath)) != null ? _e : extractContent(json);
4070
4740
  if (text && typeof text === "string") yield text;
4071
4741
  } catch (e) {
4072
4742
  }
@@ -4094,18 +4764,33 @@ ${context != null ? context : "None"}` },
4094
4764
  const isSelfHost = this.baseUrl.includes("retrivora.com") || this.baseUrl.includes("localhost");
4095
4765
  if (isSelfHost || Boolean(process.env.VERCEL)) {
4096
4766
  const _g2 = globalThis;
4097
- if (typeof _g2.__retrivoraDispatchEmbedding === "function") {
4767
+ let dispatch = _g2.__retrivoraDispatchEmbedding;
4768
+ if (typeof dispatch !== "function") {
4098
4769
  try {
4099
- const res = await _g2.__retrivoraDispatchEmbedding({
4770
+ const gateway = await Promise.resolve().then(() => (init_router(), router_exports));
4771
+ if (gateway == null ? void 0 : gateway.dispatchEmbedding) {
4772
+ _g2.__retrivoraDispatchChat = gateway.dispatchChatCompletion;
4773
+ _g2.__retrivoraDispatchEmbedding = gateway.dispatchEmbedding;
4774
+ dispatch = gateway.dispatchEmbedding;
4775
+ }
4776
+ } catch (e) {
4777
+ }
4778
+ }
4779
+ if (typeof dispatch === "function") {
4780
+ try {
4781
+ const res = await dispatch({
4100
4782
  model: this.model,
4101
4783
  input: text
4102
4784
  }, this.apiKey);
4103
4785
  if ((_c = (_b = res == null ? void 0 : res.data) == null ? void 0 : _b[0]) == null ? void 0 : _c.embedding) {
4104
4786
  return res.data[0].embedding;
4105
4787
  }
4788
+ throw new Error(`[UniversalLLMAdapter] In-process embedding dispatch returned invalid vector for model: ${this.model}`);
4106
4789
  } catch (dispatchErr) {
4107
4790
  throw dispatchErr;
4108
4791
  }
4792
+ } else {
4793
+ 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.`);
4109
4794
  }
4110
4795
  }
4111
4796
  const { data } = await this.http.post(path2, payload);
@@ -6090,8 +6775,8 @@ var IntentClassifier = class {
6090
6775
  }
6091
6776
  // ─── Intent Heuristic Checkers ─────────────────────────────────────────────
6092
6777
  static isInformationLookup(query) {
6093
- 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)) {
6094
- 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)) {
6095
6780
  return true;
6096
6781
  }
6097
6782
  }
@@ -6128,7 +6813,7 @@ var Rule1SpecificInfoRule = class {
6128
6813
  }
6129
6814
  evaluate(context, intent) {
6130
6815
  const q = (context.userQuery || "").toLowerCase().trim();
6131
- 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);
6132
6817
  const isNonVisual = !/\b(compare|versus|vs\.?|trend|monthly|revenue|best|top 10|chart|table|list|grid)\b/i.test(q);
6133
6818
  if (isFactQuery && isNonVisual) {
6134
6819
  return {
@@ -6967,7 +7652,7 @@ ${schemaProfileText}` : ""}`;
6967
7652
  }
6968
7653
  // ─── Transform Helpers ────────────────────────────────────────────────────
6969
7654
  static transformToProductCarousel(data, config, trainedSchema) {
6970
- const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null).slice(0, 15);
7655
+ const products = data.map((item) => this.extractProductInfo(item, config, trainedSchema)).filter((p) => p !== null);
6971
7656
  return {
6972
7657
  type: "product_carousel",
6973
7658
  title: "Recommended Products",
@@ -7347,7 +8032,8 @@ ${schemaProfileText}` : ""}`;
7347
8032
  return fieldCount.size > 2;
7348
8033
  }
7349
8034
  static profileData(data) {
7350
- const records = data.map((item) => {
8035
+ const records = (data || []).filter((item) => Boolean(item && typeof item === "object")).map((item) => {
8036
+ var _a2, _b;
7351
8037
  const fields2 = {};
7352
8038
  Object.entries(item.metadata || {}).forEach(([key, value]) => {
7353
8039
  const primitive = this.toPrimitive(value);
@@ -7356,8 +8042,8 @@ ${schemaProfileText}` : ""}`;
7356
8042
  if (!fields2.content && item.content) fields2.content = item.content.substring(0, 500);
7357
8043
  return {
7358
8044
  id: item.id,
7359
- content: item.content,
7360
- score: item.score,
8045
+ content: (_a2 = item.content) != null ? _a2 : "",
8046
+ score: (_b = item.score) != null ? _b : 0,
7361
8047
  fields: fields2,
7362
8048
  source: item
7363
8049
  };
@@ -7414,6 +8100,11 @@ ${schemaProfileText}` : ""}`;
7414
8100
  }
7415
8101
  static chooseAutomaticVisualization(data, profile, query) {
7416
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
+ }
7417
8108
  if (profile.dateFields.length > 0 && profile.numericFields.length > 0) {
7418
8109
  return this.transformToLineChart(profile);
7419
8110
  }
@@ -7529,6 +8220,7 @@ ${schemaProfileText}` : ""}`;
7529
8220
  return Array.from(categories);
7530
8221
  }
7531
8222
  static getProductCategory(item) {
8223
+ if (!item) return null;
7532
8224
  const meta = item.metadata || {};
7533
8225
  const metadataCategory = resolveMetadataValue(meta, "category");
7534
8226
  if (this.isUsableCategory(metadataCategory)) return String(metadataCategory).trim();
@@ -7645,6 +8337,7 @@ ${schemaProfileText}` : ""}`;
7645
8337
  if (!fields.has(normalized)) fields.set(normalized, clean);
7646
8338
  };
7647
8339
  data.forEach((item) => {
8340
+ if (!item) return;
7648
8341
  Object.keys(item.metadata || {}).forEach(addField);
7649
8342
  for (const match of (item.content || "").matchAll(/(?:^|\n)\s*([A-Za-z][A-Za-z0-9_ /-]{1,50})\s*[:\-–]\s*([^\n]+)/g)) {
7650
8343
  addField(match[1]);
@@ -7761,6 +8454,7 @@ ${schemaProfileText}` : ""}`;
7761
8454
  return true;
7762
8455
  }
7763
8456
  static extractStockQuantity(item) {
8457
+ if (!item) return null;
7764
8458
  const meta = item.metadata || {};
7765
8459
  const stockValue = resolveMetadataValue(meta, "stock");
7766
8460
  const numericStock = this.toFiniteNumber(stockValue);
@@ -8460,7 +9154,7 @@ ${m.content}`).join("\n\n---\n\n");
8460
9154
  */
8461
9155
  askStreamInternal(_0) {
8462
9156
  return __asyncGenerator(this, arguments, function* (question, history = [], namespace) {
8463
- 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;
9157
+ 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;
8464
9158
  yield new __await(this.initialize());
8465
9159
  const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
8466
9160
  const topK = (_b = (_a2 = this.config.rag) == null ? void 0 : _a2.topK) != null ? _b : 5;
@@ -8503,8 +9197,8 @@ ${m.content}`).join("\n\n---\n\n");
8503
9197
  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;
8504
9198
  const hasMetadataFilter = filter.metadata && Object.keys(filter.metadata).length > 0;
8505
9199
  const hasNumericPredicates = Array.isArray(filter.__numericPredicates) && filter.__numericPredicates.length > 0;
8506
- const wantsExhaustiveList = hasNumericPredicates || hasMetadataFilter || /\b(list|all|show|provide|give|get|browse|find|search|display)\b/i.test(question);
8507
- const retrievalLimit = wantsExhaustiveList ? Math.max(topK * 20, 100) : topK * 2;
9200
+ const wantsExhaustiveList = true;
9201
+ const retrievalLimit = Math.max(topK * 50, 1e3);
8508
9202
  const rawSources = ((strategyResult === "vector" || strategyResult === "both") && queryVector && queryVector.length > 0 ? yield new __await(this.vectorDB.query(queryVector, retrievalLimit, ns, filter)) : []).filter((s) => Boolean(s && typeof s === "object"));
8509
9203
  console.log("[Pipeline] Raw vectorDB.query response:", {
8510
9204
  rawCount: rawSources.length,
@@ -8528,40 +9222,29 @@ ${m.content}`).join("\n\n---\n\n");
8528
9222
  var _a3;
8529
9223
  return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= scoreThreshold;
8530
9224
  });
8531
- const rerankLimit = wantsExhaustiveList ? retrievalLimit : topK;
9225
+ const rerankLimit = Math.max(retrievalLimit, fullSources.length);
8532
9226
  const useReranking = arch !== "naive" && (arch === "retrieve-and-rerank" || ((_m = this.config.rag) == null ? void 0 : _m.useReranking));
8533
9227
  if (!hasNumericPredicates && useReranking) {
8534
9228
  fullSources = (yield new __await(this.reranker.rerank(fullSources, question, rerankLimit))).filter((s) => Boolean(s && typeof s === "object"));
8535
- } else if (!wantsExhaustiveList) {
8536
- fullSources = fullSources.slice(0, topK);
8537
9229
  }
8538
9230
  const rerankMs = performance.now() - rerankStart;
8539
- let context = fullSources.length ? fullSources.map((m, i) => {
9231
+ const totalCount = fullSources.length;
9232
+ const promptSources = fullSources.slice(0, 15);
9233
+ 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]
9234
+
9235
+ ` + promptSources.map((m, i) => {
8540
9236
  var _a3;
8541
9237
  return `[Source ${i + 1}]
8542
9238
  ${(_a3 = m == null ? void 0 : m.content) != null ? _a3 : ""}`;
8543
9239
  }).join("\n\n---\n\n") : "No relevant context found.";
8544
- let displayCount = 15;
8545
- if (hasMetadataFilter) {
8546
- displayCount = fullSources.length;
8547
- } else {
8548
- const baseThreshold = Math.max(scoreThreshold, 0.4);
8549
- const highlyRelevant = fullSources.filter((m) => {
8550
- var _a3;
8551
- return ((_a3 = m == null ? void 0 : m.score) != null ? _a3 : 0) >= baseThreshold;
8552
- });
8553
- displayCount = Math.max(highlyRelevant.length, topK);
8554
- if (displayCount > 15) {
8555
- displayCount = 15;
8556
- }
8557
- }
8558
9240
  const sources = [...fullSources].filter((s) => Boolean(s && typeof s === "object")).sort((a, b) => {
8559
9241
  var _a3, _b2;
8560
9242
  return ((_a3 = b == null ? void 0 : b.score) != null ? _a3 : 0) - ((_b2 = a == null ? void 0 : a.score) != null ? _b2 : 0);
8561
- }).slice(0, displayCount);
9243
+ });
8562
9244
  console.log("[Pipeline] Final sources for prompt & UI:", {
8563
9245
  count: sources.length,
8564
- sources: sources.map((s, idx) => {
9246
+ totalRawCount: rawSources.length,
9247
+ sources: sources.slice(0, 10).map((s, idx) => {
8565
9248
  var _a3;
8566
9249
  return {
8567
9250
  rank: idx + 1,
@@ -8761,7 +9444,7 @@ ${context}`;
8761
9444
  }
8762
9445
  yield fullReply;
8763
9446
  }
8764
- 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;
9447
+ const runHallucination = ((_w = this.config.llm.options) == null ? void 0 : _w.hallucinationScoring) === true;
8765
9448
  if (runHallucination) {
8766
9449
  hallucinationScoringPromise = scoreHallucination(this.llmProvider, fullReply, context).catch(() => void 0);
8767
9450
  }
@@ -8770,7 +9453,7 @@ ${context}`;
8770
9453
  const latency = {
8771
9454
  embedMs: Math.round(embedMs),
8772
9455
  retrieveMs: Math.round(retrieveMs),
8773
- rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_y = this.config.rag) == null ? void 0 : _y.useReranking)) ? Math.round(rerankMs) : void 0,
9456
+ rerankMs: arch !== "naive" && (arch === "retrieve-and-rerank" || ((_x = this.config.rag) == null ? void 0 : _x.useReranking)) ? Math.round(rerankMs) : void 0,
8774
9457
  generateMs: Math.round(generateMs),
8775
9458
  totalMs: Math.round(totalMs)
8776
9459
  };
@@ -8783,7 +9466,7 @@ ${context}`;
8783
9466
  totalTokens: promptTokens + completionTokens,
8784
9467
  estimatedCostUsd: estimateCostUsd(promptTokens, completionTokens, this.config.llm.model)
8785
9468
  };
8786
- const awaitHallucination = ((_z = this.config.llm.options) == null ? void 0 : _z.awaitHallucination) === true;
9469
+ const awaitHallucination = ((_y = this.config.llm.options) == null ? void 0 : _y.awaitHallucination) === true;
8787
9470
  const [uiTransformation, hallucinationResult] = yield new __await(Promise.all([
8788
9471
  uiTransformationPromise,
8789
9472
  awaitHallucination ? hallucinationScoringPromise : Promise.resolve(void 0)
@@ -8812,10 +9495,10 @@ ${context}`;
8812
9495
  hallucinationReason: hScore.reason
8813
9496
  } : {});
8814
9497
  const trace = buildTrace(hallucinationResult);
8815
- const isTelemetryActive = (_B = (_A = this.config.telemetry) == null ? void 0 : _A.enabled) != null ? _B : Boolean(this.config.licenseKey);
9498
+ const isTelemetryActive = (_A = (_z = this.config.telemetry) == null ? void 0 : _z.enabled) != null ? _A : Boolean(this.config.licenseKey);
8816
9499
  if (isTelemetryActive) {
8817
9500
  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";
8818
- const telemetryUrl = ((_C = this.config.telemetry) == null ? void 0 : _C.url) || process.env.TELEMETRY_URL || process.env.NEXT_PUBLIC_TELEMETRY_URL || defaultUrl;
9501
+ const telemetryUrl = ((_B = this.config.telemetry) == null ? void 0 : _B.url) || process.env.TELEMETRY_URL || process.env.NEXT_PUBLIC_TELEMETRY_URL || defaultUrl;
8819
9502
  const absoluteUrl = telemetryUrl.startsWith("http") ? telemetryUrl : (process.env.NEXT_PUBLIC_APP_URL || `http://localhost:${process.env.PORT || 3e3}`) + telemetryUrl;
8820
9503
  (async () => {
8821
9504
  try {
@@ -8874,9 +9557,8 @@ ${context}`;
8874
9557
  { visualizationHint: "product_browse", recommendedChart: "text", filterInStockOnly: false, wantsExplicitTable: false, isTemporal: false, isComparison: false, language: "en" }
8875
9558
  );
8876
9559
  }
8877
- const isLocalProvider = this.config.llm.provider === "ollama";
8878
- const disableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.disableLlmUiTransform) === true;
8879
- if (forceDeterministic || isLocalProvider || disableLlmUiTransform) {
9560
+ const enableLlmUiTransform = ((_a2 = this.config.llm.options) == null ? void 0 : _a2.enableLlmUiTransform) === true;
9561
+ if (forceDeterministic || !enableLlmUiTransform) {
8880
9562
  return UITransformer.transform(question, sources, this.config, cachedSchema);
8881
9563
  }
8882
9564
  try {
@@ -9033,7 +9715,10 @@ ${context}`;
9033
9715
  Focus on extracting the core intent and entities. Do not answer the question, just rewrite it.
9034
9716
 
9035
9717
  History:
9036
- ${history.map((m) => `${m.role}: ${m.content}`).join("\n")}
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")}
9037
9722
 
9038
9723
  New Question: ${question}
9039
9724
 
@@ -9057,8 +9742,11 @@ Optimized Search Query:`;
9057
9742
  const ns = formatNamespace(namespace != null ? namespace : this.config.projectId);
9058
9743
  try {
9059
9744
  const { sources } = await this.retrieve(query, { namespace: ns, topK: 5 });
9060
- if (sources.length === 0) return [];
9061
- const context = sources.map((s) => s.content).join("\n\n---\n\n");
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");
9062
9750
  const prompt = `Based on the following snippets from a document, what are at least 5 short, relevant questions a user might ask?
9063
9751
  Focus on questions that can be answered by the context.
9064
9752
  Keep each question under 10 words and make them very specific to the content.