@retrivora-ai/rag-engine 1.7.5 → 1.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DocumentChunker-BXOUMKoP.d.ts → DocumentChunker-DMZVv6hi.d.ts} +1 -1
- package/dist/{DocumentChunker-D1dg5iCi.d.mts → DocumentChunker-wKE98F_G.d.mts} +1 -1
- package/dist/{chunk-QOO37S2Z.mjs → chunk-UHGYLTTY.mjs} +894 -883
- package/dist/handlers/index.d.mts +2 -2
- package/dist/handlers/index.d.ts +2 -2
- package/dist/handlers/index.js +894 -883
- package/dist/handlers/index.mjs +1 -1
- package/dist/{index-BejNscWZ.d.mts → index-B1u4loP6.d.mts} +1 -1
- package/dist/{index-CbkMJvu5.d.ts → index-D9w9fLjh.d.ts} +1 -1
- package/dist/{index-Cti1u0y1.d.mts → index-DfsVx0a4.d.mts} +1 -0
- package/dist/{index-Cti1u0y1.d.ts → index-DfsVx0a4.d.ts} +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +185 -5
- package/dist/index.mjs +318 -138
- package/dist/server.d.mts +5 -5
- package/dist/server.d.ts +5 -5
- package/dist/server.js +1251 -1236
- package/dist/server.mjs +11 -5
- package/package.json +1 -1
- package/src/components/MessageBubble.tsx +8 -0
- package/src/core/Pipeline.ts +19 -3
- package/src/hooks/useRagChat.ts +12 -2
- package/src/providers/vectordb/MultiTablePostgresProvider.ts +21 -9
- package/src/types/chat.ts +1 -0
package/dist/server.mjs
CHANGED
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
sseFrame,
|
|
40
40
|
sseMetaFrame,
|
|
41
41
|
sseTextFrame
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-UHGYLTTY.mjs";
|
|
43
43
|
import "./chunk-YLTMFW4M.mjs";
|
|
44
44
|
import {
|
|
45
45
|
PineconeProvider
|
|
@@ -325,15 +325,21 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
325
325
|
).map((hint) => hint.value.trim().toLowerCase()).filter(Boolean) : [];
|
|
326
326
|
console.log(`[MultiTablePostgresProvider] queryText: "${queryText}"`);
|
|
327
327
|
console.log(`[MultiTablePostgresProvider] entityHints: [${entityHints.join(", ")}]`);
|
|
328
|
-
const
|
|
329
|
-
|
|
328
|
+
const getDynamicKeywordQuery = () => {
|
|
329
|
+
if (entityHints.length > 0) {
|
|
330
|
+
return entityHints.map((h) => h.includes(" ") ? `"${h}"` : h).join(" & ");
|
|
331
|
+
}
|
|
332
|
+
if (queryText) {
|
|
333
|
+
return queryText.toLowerCase().replace(/\b(show|me|the|product[s]?|item[s]?|card[s]?|of|category|find|list|browse|what|are|display|all|under|for|in|with|about)\b/g, "").trim().replace(/\s+/g, " & ");
|
|
334
|
+
}
|
|
335
|
+
return "";
|
|
330
336
|
};
|
|
337
|
+
const dynamicKeywordQuery = getDynamicKeywordQuery();
|
|
331
338
|
const queryPromises = this.tables.map(async (table) => {
|
|
332
339
|
try {
|
|
333
340
|
let sqlQuery = "";
|
|
334
341
|
let params = [];
|
|
335
342
|
if (queryText) {
|
|
336
|
-
const cleanedText = cleanKeywordQuery(queryText) || queryText;
|
|
337
343
|
const hasEntityHints = entityHints.length > 0;
|
|
338
344
|
const exactNameScoreExpr = hasEntityHints ? `+ (
|
|
339
345
|
SELECT COALESCE(MAX(
|
|
@@ -352,7 +358,7 @@ var MultiTablePostgresProvider = class extends BaseVectorProvider {
|
|
|
352
358
|
ORDER BY hybrid_score DESC
|
|
353
359
|
LIMIT 50
|
|
354
360
|
`;
|
|
355
|
-
params = [vectorLiteral,
|
|
361
|
+
params = [vectorLiteral, dynamicKeywordQuery];
|
|
356
362
|
} else {
|
|
357
363
|
sqlQuery = `
|
|
358
364
|
SELECT *,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@retrivora-ai/rag-engine",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.7",
|
|
4
4
|
"description": "Retrivora AI is a plug-and-play AI engine for RAG chat experiences — generic vector DB + LLM provider, embeddable or standalone.",
|
|
5
5
|
"author": "Abhinav Alkuchi",
|
|
6
6
|
"license": "MIT",
|
|
@@ -9,6 +9,7 @@ import { ChatViewportSize } from '../types/props';
|
|
|
9
9
|
import { SourceCard } from './SourceCard';
|
|
10
10
|
import { ProductCarousel } from './ProductCarousel';
|
|
11
11
|
import { DynamicChart } from './DynamicChart';
|
|
12
|
+
import { VisualizationRenderer } from './VisualizationRenderer';
|
|
12
13
|
|
|
13
14
|
// ─── JSON sanitization ────────────────────────────────────────────────────────
|
|
14
15
|
// Order matters: each step is a targeted fix, no step undoes a previous one.
|
|
@@ -988,6 +989,13 @@ export function MessageBubble({
|
|
|
988
989
|
</ReactMarkdown>
|
|
989
990
|
)}
|
|
990
991
|
|
|
992
|
+
{/* Automated UI Fallback (if LLM failed to output structured block but UITransformer found data) */}
|
|
993
|
+
{!isUser && !structuredContent.payload && message.uiTransformation && (
|
|
994
|
+
<div className="mt-4 border-t border-slate-100 dark:border-white/5 pt-4">
|
|
995
|
+
<VisualizationRenderer data={message.uiTransformation} />
|
|
996
|
+
</div>
|
|
997
|
+
)}
|
|
998
|
+
|
|
991
999
|
{isStreaming && message.content && (
|
|
992
1000
|
<span className="inline-block w-1.5 h-3.5 ml-1 bg-emerald-500 animate-pulse align-middle" />
|
|
993
1001
|
)}
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -13,6 +13,7 @@ import { BatchProcessor, BatchOptions } from './BatchProcessor';
|
|
|
13
13
|
import { EmbeddingStrategyResolver } from '../config/EmbeddingStrategy';
|
|
14
14
|
import { QueryProcessor } from './QueryProcessor';
|
|
15
15
|
import { IngestDocument, ChatResponse, VectorMatch, GraphSearchResult, RetrievalResult, UpsertDocument } from '../types';
|
|
16
|
+
import { UITransformer } from '../utils/UITransformer';
|
|
16
17
|
|
|
17
18
|
// ─── LRU Embedding Cache ───────────────────────────────────────────────────────
|
|
18
19
|
|
|
@@ -203,11 +204,14 @@ Classify the query into ONE of the following intents:
|
|
|
203
204
|
|
|
204
205
|
## 5. DATA RULES
|
|
205
206
|
|
|
206
|
-
- NEVER hallucinate fields
|
|
207
|
+
- NEVER hallucinate fields or data
|
|
207
208
|
- ONLY use retrieved vector DB data
|
|
208
209
|
- NO placeholders ("...", "N/A")
|
|
209
210
|
- If image/link missing → REMOVE FIELD
|
|
210
211
|
- Aggregate BEFORE rendering chart
|
|
212
|
+
- IF NO DATA IS FOUND in the retrieved context:
|
|
213
|
+
→ DO NOT output a \`\`\`ui\`\`\` block
|
|
214
|
+
→ Instead, state clearly that no relevant products or data were found.
|
|
211
215
|
|
|
212
216
|
---
|
|
213
217
|
|
|
@@ -227,6 +231,8 @@ Classify the query into ONE of the following intents:
|
|
|
227
231
|
- ALWAYS return EXACTLY ONE \`\`\`ui\`\`\` block
|
|
228
232
|
- JSON must be VALID
|
|
229
233
|
- No explanation inside block
|
|
234
|
+
- NEVER use ASCII charts, Markdown tables, or text-based drawings for data.
|
|
235
|
+
- If data is tabular or statistical, ALWAYS use the \`\`\`ui\`\`\` block.
|
|
230
236
|
|
|
231
237
|
---
|
|
232
238
|
|
|
@@ -559,8 +565,18 @@ User: "distribution of products across categories"
|
|
|
559
565
|
yield reply;
|
|
560
566
|
}
|
|
561
567
|
|
|
562
|
-
//
|
|
563
|
-
|
|
568
|
+
// 6. Automated UI Fallback (UITransformer)
|
|
569
|
+
// This provides a secondary, rule-based visualization frame in case the LLM
|
|
570
|
+
// fails to adhere to the strict protocol or outputs a text fallback.
|
|
571
|
+
const uiTransformation = UITransformer.transform(question, sources);
|
|
572
|
+
|
|
573
|
+
// Yield retrieval metadata and automated UI transformation at the end
|
|
574
|
+
yield {
|
|
575
|
+
reply: '',
|
|
576
|
+
sources,
|
|
577
|
+
graphData,
|
|
578
|
+
ui_transformation: uiTransformation
|
|
579
|
+
} as ChatResponse;
|
|
564
580
|
|
|
565
581
|
} catch (error) {
|
|
566
582
|
throw new Error(`[Pipeline] Stream failed: ${error instanceof Error ? error.message : String(error)}`);
|
package/src/hooks/useRagChat.ts
CHANGED
|
@@ -27,7 +27,8 @@ import { useStoredMessages } from './useStoredMessages';
|
|
|
27
27
|
interface SseTextFrame { type: 'text'; text: string }
|
|
28
28
|
interface SseMetaFrame { type: 'metadata'; sources?: VectorMatch[] }
|
|
29
29
|
interface SseErrorFrame { type: 'error'; error: string }
|
|
30
|
-
|
|
30
|
+
interface SseUiFrame { type: 'ui_transformation'; data: any }
|
|
31
|
+
type SseFrame = SseTextFrame | SseMetaFrame | SseErrorFrame | SseUiFrame;
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* Parse all complete SSE frames from a raw chunk string.
|
|
@@ -124,6 +125,7 @@ export function useRagChat(
|
|
|
124
125
|
const decoder = new TextDecoder();
|
|
125
126
|
let assistantContent = '';
|
|
126
127
|
let sources: VectorMatch[] = [];
|
|
128
|
+
let uiTransformation: any = null;
|
|
127
129
|
// Buffer for partial SSE frames that arrive split across reads
|
|
128
130
|
let buffer = '';
|
|
129
131
|
|
|
@@ -157,6 +159,8 @@ export function useRagChat(
|
|
|
157
159
|
assistantContent += frame.text;
|
|
158
160
|
} else if (frame.type === 'metadata') {
|
|
159
161
|
sources = frame.sources ?? [];
|
|
162
|
+
} else if (frame.type === 'ui_transformation') {
|
|
163
|
+
uiTransformation = frame.data;
|
|
160
164
|
} else if (frame.type === 'error') {
|
|
161
165
|
setError(frame.error || 'Stream error');
|
|
162
166
|
}
|
|
@@ -166,7 +170,12 @@ export function useRagChat(
|
|
|
166
170
|
setMessages((prev) =>
|
|
167
171
|
prev.map((msg) =>
|
|
168
172
|
msg.id === assistantMessageId
|
|
169
|
-
? {
|
|
173
|
+
? {
|
|
174
|
+
...msg,
|
|
175
|
+
content: assistantContent,
|
|
176
|
+
sources: sources.length > 0 ? sources : msg.sources,
|
|
177
|
+
uiTransformation: uiTransformation || (msg as any).uiTransformation
|
|
178
|
+
}
|
|
170
179
|
: msg
|
|
171
180
|
)
|
|
172
181
|
);
|
|
@@ -185,6 +194,7 @@ export function useRagChat(
|
|
|
185
194
|
role: 'assistant',
|
|
186
195
|
content: assistantContent,
|
|
187
196
|
sources: sources.length > 0 ? sources : undefined,
|
|
197
|
+
uiTransformation: uiTransformation || undefined,
|
|
188
198
|
createdAt: new Date().toISOString(),
|
|
189
199
|
};
|
|
190
200
|
onReply?.(finalAssistantMessage);
|
|
@@ -151,22 +151,34 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
151
151
|
console.log(`[MultiTablePostgresProvider] queryText: "${queryText}"`);
|
|
152
152
|
console.log(`[MultiTablePostgresProvider] entityHints: [${entityHints.join(', ')}]`);
|
|
153
153
|
|
|
154
|
-
//
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
154
|
+
// Dynamic Keyword Search: Prioritize intelligently extracted hints over raw text
|
|
155
|
+
const getDynamicKeywordQuery = () => {
|
|
156
|
+
if (entityHints.length > 0) {
|
|
157
|
+
// Use extracted entities as high-signal keywords
|
|
158
|
+
return entityHints
|
|
159
|
+
.map(h => h.includes(' ') ? `"${h}"` : h) // Wrap multi-word hints in quotes
|
|
160
|
+
.join(' & ');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (queryText) {
|
|
164
|
+
// Fallback to cleaned raw text if no high-signal hints were extracted
|
|
165
|
+
return queryText
|
|
166
|
+
.toLowerCase()
|
|
167
|
+
.replace(/\b(show|me|the|product[s]?|item[s]?|card[s]?|of|category|find|list|browse|what|are|display|all|under|for|in|with|about)\b/g, '')
|
|
168
|
+
.trim()
|
|
169
|
+
.replace(/\s+/g, ' & ');
|
|
170
|
+
}
|
|
171
|
+
return '';
|
|
161
172
|
};
|
|
162
173
|
|
|
174
|
+
const dynamicKeywordQuery = getDynamicKeywordQuery();
|
|
175
|
+
|
|
163
176
|
const queryPromises = this.tables.map(async (table) => {
|
|
164
177
|
try {
|
|
165
178
|
let sqlQuery = '';
|
|
166
179
|
let params: unknown[] = [];
|
|
167
180
|
|
|
168
181
|
if (queryText) {
|
|
169
|
-
const cleanedText = cleanKeywordQuery(queryText) || queryText;
|
|
170
182
|
const hasEntityHints = entityHints.length > 0;
|
|
171
183
|
const exactNameScoreExpr = hasEntityHints
|
|
172
184
|
? `+ (
|
|
@@ -189,7 +201,7 @@ export class MultiTablePostgresProvider extends BaseVectorProvider {
|
|
|
189
201
|
ORDER BY hybrid_score DESC
|
|
190
202
|
LIMIT 50
|
|
191
203
|
`;
|
|
192
|
-
params = [vectorLiteral,
|
|
204
|
+
params = [vectorLiteral, dynamicKeywordQuery];
|
|
193
205
|
} else {
|
|
194
206
|
// Fallback to Vector-only Search
|
|
195
207
|
sqlQuery = `
|