@retrivora-ai/rag-engine 1.5.5 → 1.5.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/{chunk-Q4MDH6C4.mjs → chunk-ID2Q4CF7.mjs} +2 -0
- package/dist/handlers/index.js +2 -0
- package/dist/handlers/index.mjs +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +118 -40
- package/dist/index.mjs +118 -40
- package/dist/server.js +2 -0
- package/dist/server.mjs +1 -1
- package/package.json +1 -1
- package/src/components/ChatWindow.tsx +26 -0
- package/src/components/DynamicChart.tsx +32 -16
- package/src/components/MessageBubble.tsx +112 -27
- package/src/components/ProductCarousel.tsx +2 -2
- package/src/core/Pipeline.ts +2 -0
- package/src/types/props.ts +3 -0
|
@@ -5,6 +5,7 @@ import { Bot, User, ChevronDown, ChevronRight } from 'lucide-react';
|
|
|
5
5
|
import ReactMarkdown from 'react-markdown';
|
|
6
6
|
import remarkGfm from 'remark-gfm';
|
|
7
7
|
import { MessageBubbleProps, Product } from '../types';
|
|
8
|
+
import { ChatViewportSize } from '../types/props';
|
|
8
9
|
import { SourceCard } from './SourceCard';
|
|
9
10
|
import { ProductCarousel } from './ProductCarousel';
|
|
10
11
|
import { DynamicChart } from './DynamicChart';
|
|
@@ -90,6 +91,17 @@ function sanitizeJson(raw: string): string {
|
|
|
90
91
|
return s;
|
|
91
92
|
}
|
|
92
93
|
|
|
94
|
+
function extractLikelyJsonBlock(raw: string): string {
|
|
95
|
+
const trimmed = raw.trim();
|
|
96
|
+
const objectStart = trimmed.indexOf('{');
|
|
97
|
+
const arrayStart = trimmed.indexOf('[');
|
|
98
|
+
|
|
99
|
+
const starts = [objectStart, arrayStart].filter((index) => index >= 0);
|
|
100
|
+
if (starts.length === 0) return trimmed;
|
|
101
|
+
|
|
102
|
+
return trimmed.slice(Math.min(...starts));
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
// ─── Tiny helpers ─────────────────────────────────────────────────────────────
|
|
94
106
|
|
|
95
107
|
function resolveImage(data: Record<string, unknown>): string | undefined {
|
|
@@ -130,7 +142,9 @@ interface TableConfig {
|
|
|
130
142
|
data: Record<string, unknown>[];
|
|
131
143
|
}
|
|
132
144
|
|
|
133
|
-
function DataTable({ config }: { config: TableConfig }) {
|
|
145
|
+
function DataTable({ config, viewportSize = 'large' }: { config: TableConfig; viewportSize?: ChatViewportSize }) {
|
|
146
|
+
const isCompact = viewportSize === 'compact';
|
|
147
|
+
const isMedium = viewportSize === 'medium';
|
|
134
148
|
const keys = React.useMemo<string[]>(() => {
|
|
135
149
|
// Priority 1: explicit columns list
|
|
136
150
|
if (Array.isArray(config.columns) && config.columns.length) {
|
|
@@ -169,13 +183,13 @@ function DataTable({ config }: { config: TableConfig }) {
|
|
|
169
183
|
)}
|
|
170
184
|
|
|
171
185
|
<div className="overflow-x-auto">
|
|
172
|
-
<table className=
|
|
186
|
+
<table className={`w-full text-left border-collapse ${isCompact ? 'min-w-[240px] text-xs' : isMedium ? 'min-w-[280px] text-[13px]' : 'min-w-[320px] text-sm'}`}>
|
|
173
187
|
<thead className="bg-slate-50 dark:bg-white/5 border-b border-slate-200 dark:border-white/10">
|
|
174
188
|
<tr>
|
|
175
189
|
{keys.map(k => (
|
|
176
190
|
<th
|
|
177
191
|
key={k}
|
|
178
|
-
className=
|
|
192
|
+
className={`${isCompact ? 'px-2.5 py-2' : 'px-4 py-3'} font-semibold text-slate-700 dark:text-white/90 whitespace-nowrap`}
|
|
179
193
|
>
|
|
180
194
|
{k}
|
|
181
195
|
</th>
|
|
@@ -191,7 +205,7 @@ function DataTable({ config }: { config: TableConfig }) {
|
|
|
191
205
|
{keys.map(k => (
|
|
192
206
|
<td
|
|
193
207
|
key={k}
|
|
194
|
-
className=
|
|
208
|
+
className={`${isCompact ? 'px-2.5 py-2' : 'px-4 py-3'} text-slate-600 dark:text-white/70 whitespace-nowrap`}
|
|
195
209
|
>
|
|
196
210
|
{formatCell(row[k])}
|
|
197
211
|
</td>
|
|
@@ -227,14 +241,63 @@ interface UIConfig {
|
|
|
227
241
|
insights?: string[];
|
|
228
242
|
type?: string;
|
|
229
243
|
items?: Record<string, unknown>[];
|
|
244
|
+
rows?: Record<string, unknown>[];
|
|
245
|
+
products?: Record<string, unknown>[];
|
|
246
|
+
results?: Record<string, unknown>[];
|
|
230
247
|
}
|
|
231
248
|
|
|
232
|
-
|
|
249
|
+
interface RawUIConfig extends Omit<UIConfig, 'data' | 'items' | 'rows' | 'products' | 'results'> {
|
|
250
|
+
data: Array<Record<string, unknown> | unknown[]>;
|
|
251
|
+
items?: Array<Record<string, unknown> | unknown[]>;
|
|
252
|
+
rows?: Array<Record<string, unknown> | unknown[]>;
|
|
253
|
+
products?: Array<Record<string, unknown> | unknown[]>;
|
|
254
|
+
results?: Array<Record<string, unknown> | unknown[]>;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function normalizeTabularRows(
|
|
258
|
+
rows: Array<Record<string, unknown> | unknown[]> | undefined,
|
|
259
|
+
columns?: string[],
|
|
260
|
+
): Record<string, unknown>[] {
|
|
261
|
+
if (!Array.isArray(rows)) return [];
|
|
262
|
+
|
|
263
|
+
return rows
|
|
264
|
+
.map((row) => {
|
|
265
|
+
if (Array.isArray(row)) {
|
|
266
|
+
const keys = Array.isArray(columns) && columns.length > 0
|
|
267
|
+
? columns
|
|
268
|
+
: row.map((_, index) => `column_${index + 1}`);
|
|
269
|
+
|
|
270
|
+
return keys.reduce<Record<string, unknown>>((acc, key, index) => {
|
|
271
|
+
acc[key] = row[index];
|
|
272
|
+
return acc;
|
|
273
|
+
}, {});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (row && typeof row === 'object') {
|
|
277
|
+
return row as Record<string, unknown>;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return { value: row };
|
|
281
|
+
})
|
|
282
|
+
.filter((row) => Object.keys(row).length > 0);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function resolveStructuredRows(config: Partial<RawUIConfig> & Record<string, unknown>) {
|
|
286
|
+
if (Array.isArray(config.data) && config.data.length > 0) return config.data;
|
|
287
|
+
if (Array.isArray(config.rows) && config.rows.length > 0) return config.rows;
|
|
288
|
+
if (Array.isArray(config.items) && config.items.length > 0) return config.items;
|
|
289
|
+
if (Array.isArray(config.products) && config.products.length > 0) return config.products;
|
|
290
|
+
if (Array.isArray(config.results) && config.results.length > 0) return config.results;
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAddToCart, viewportSize = 'large' }: {
|
|
233
295
|
rawContent: string;
|
|
234
296
|
primaryColor?: string;
|
|
235
297
|
accentColor?: string;
|
|
236
298
|
isStreaming?: boolean;
|
|
237
299
|
onAddToCart?: (product: Product) => void;
|
|
300
|
+
viewportSize?: ChatViewportSize;
|
|
238
301
|
}) {
|
|
239
302
|
const result = React.useMemo<{ config: UIConfig } | { error: string } | { loading: true }>(() => {
|
|
240
303
|
if (isStreaming) return { loading: true };
|
|
@@ -243,17 +306,26 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
243
306
|
.replace(/^```[a-z]*\s*/i, '')
|
|
244
307
|
.replace(/```\s*$/, '')
|
|
245
308
|
.trim();
|
|
246
|
-
const parsed = JSON.parse(sanitizeJson(clean));
|
|
247
|
-
const config = { ...parsed }
|
|
309
|
+
const parsed = JSON.parse(sanitizeJson(extractLikelyJsonBlock(clean)));
|
|
310
|
+
const config = { ...parsed } as Partial<RawUIConfig> & Record<string, unknown>;
|
|
248
311
|
|
|
249
312
|
// Smart Auto-Detection for legacy or simpler formats
|
|
250
313
|
if (!config.view) {
|
|
251
314
|
if (config.type === 'products' || Array.isArray(config.items)) {
|
|
252
315
|
config.view = 'carousel';
|
|
253
316
|
config.data = config.data || config.items || [];
|
|
254
|
-
} else if (
|
|
317
|
+
} else if (
|
|
318
|
+
(typeof config.type === 'string' && ['pie', 'bar', 'line'].includes(config.type)) ||
|
|
319
|
+
(typeof config.chartType === 'string' && ['pie', 'bar', 'line'].includes(config.chartType))
|
|
320
|
+
) {
|
|
321
|
+
const resolvedChartType =
|
|
322
|
+
config.chartType === 'pie' || config.chartType === 'bar' || config.chartType === 'line'
|
|
323
|
+
? config.chartType
|
|
324
|
+
: config.type === 'pie' || config.type === 'bar' || config.type === 'line'
|
|
325
|
+
? config.type
|
|
326
|
+
: 'bar';
|
|
255
327
|
config.view = 'chart';
|
|
256
|
-
config.chartType =
|
|
328
|
+
config.chartType = resolvedChartType;
|
|
257
329
|
config.data = config.data || [];
|
|
258
330
|
} else {
|
|
259
331
|
config.view = 'table';
|
|
@@ -261,7 +333,13 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
261
333
|
}
|
|
262
334
|
}
|
|
263
335
|
|
|
264
|
-
|
|
336
|
+
const resolvedRows = resolveStructuredRows(config);
|
|
337
|
+
const normalizedConfig: UIConfig = {
|
|
338
|
+
...(config as Omit<UIConfig, 'data'>),
|
|
339
|
+
data: normalizeTabularRows(resolvedRows, config.columns),
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
return { config: normalizedConfig };
|
|
265
343
|
} catch (err) {
|
|
266
344
|
return { error: String(err) };
|
|
267
345
|
}
|
|
@@ -281,16 +359,17 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
281
359
|
}
|
|
282
360
|
|
|
283
361
|
const { config } = result;
|
|
362
|
+
const isCompact = viewportSize === 'compact';
|
|
284
363
|
const hasInsights = Array.isArray(config.insights) && config.insights.length > 0;
|
|
285
364
|
const hasDescription = typeof config.description === 'string' && config.description.trim().length > 0;
|
|
286
365
|
|
|
287
366
|
switch (config.view) {
|
|
288
367
|
case 'chart':
|
|
289
368
|
return (
|
|
290
|
-
<div className=
|
|
291
|
-
{config.title && <h4 className=
|
|
369
|
+
<div className={`${isCompact ? 'my-4 p-3' : 'my-6 p-4'} bg-white dark:bg-slate-900 rounded-2xl border border-slate-200 dark:border-white/10 shadow-sm overflow-hidden`}>
|
|
370
|
+
{config.title && <h4 className={`${isCompact ? 'text-[11px] mb-3' : 'text-xs mb-4'} font-semibold text-slate-500 px-2`}>{config.title}</h4>}
|
|
292
371
|
{hasDescription && (
|
|
293
|
-
<p className=
|
|
372
|
+
<p className={`px-2 ${isCompact ? 'text-xs' : 'text-sm'} text-slate-500 dark:text-white/60`}>{config.description}</p>
|
|
294
373
|
)}
|
|
295
374
|
<DynamicChart
|
|
296
375
|
config={{
|
|
@@ -302,13 +381,14 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
302
381
|
}}
|
|
303
382
|
primaryColor={primaryColor}
|
|
304
383
|
accentColor={accentColor}
|
|
384
|
+
viewportSize={viewportSize}
|
|
305
385
|
/>
|
|
306
386
|
{hasInsights && (
|
|
307
387
|
<div className="mt-4 flex flex-wrap gap-2 px-2">
|
|
308
388
|
{config.insights?.map((insight) => (
|
|
309
389
|
<span
|
|
310
390
|
key={insight}
|
|
311
|
-
className=
|
|
391
|
+
className={`rounded-full border border-emerald-200 bg-emerald-50 ${isCompact ? 'px-2.5 py-1 text-[10px]' : 'px-3 py-1 text-[11px]'} font-medium text-emerald-700 dark:border-emerald-500/20 dark:bg-emerald-500/10 dark:text-emerald-300`}
|
|
312
392
|
>
|
|
313
393
|
{insight}
|
|
314
394
|
</span>
|
|
@@ -320,9 +400,9 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
320
400
|
case 'carousel':
|
|
321
401
|
return (
|
|
322
402
|
<div className="my-4">
|
|
323
|
-
{config.title && <h4 className=
|
|
403
|
+
{config.title && <h4 className={`${isCompact ? 'mb-1.5 text-[11px]' : 'mb-2 text-xs'} font-semibold text-slate-500`}>{config.title}</h4>}
|
|
324
404
|
{hasDescription && (
|
|
325
|
-
<p className=
|
|
405
|
+
<p className={`mb-3 ${isCompact ? 'text-xs' : 'text-sm'} text-slate-500 dark:text-white/60`}>{config.description}</p>
|
|
326
406
|
)}
|
|
327
407
|
<ProductCarousel products={(config.data as unknown as Product[]).map(item => ({
|
|
328
408
|
...item,
|
|
@@ -332,10 +412,10 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
332
412
|
);
|
|
333
413
|
case 'table':
|
|
334
414
|
return (
|
|
335
|
-
<div className=
|
|
336
|
-
{config.title && <h4 className=
|
|
415
|
+
<div className={`${isCompact ? 'my-3 p-3 max-h-[320px]' : 'my-4 p-4 max-h-[400px]'} bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-white/10 shadow-sm overflow-auto`}>
|
|
416
|
+
{config.title && <h4 className={`${isCompact ? 'text-[11px]' : 'text-xs'} font-semibold text-slate-500 mb-2`}>{config.title}</h4>}
|
|
337
417
|
{hasDescription && (
|
|
338
|
-
<p className=
|
|
418
|
+
<p className={`mb-3 ${isCompact ? 'text-xs' : 'text-sm'} text-slate-500 dark:text-white/60`}>{config.description}</p>
|
|
339
419
|
)}
|
|
340
420
|
<DataTable config={{
|
|
341
421
|
type: 'table',
|
|
@@ -345,7 +425,7 @@ function UIDispatcher({ rawContent, primaryColor, accentColor, isStreaming, onAd
|
|
|
345
425
|
dataKeys: config.dataKeys,
|
|
346
426
|
xAxisKey: config.xAxisKey,
|
|
347
427
|
data: config.data,
|
|
348
|
-
}} />
|
|
428
|
+
}} viewportSize={viewportSize} />
|
|
349
429
|
</div>
|
|
350
430
|
);
|
|
351
431
|
default:
|
|
@@ -364,8 +444,11 @@ export function MessageBubble({
|
|
|
364
444
|
primaryColor = '#6366f1',
|
|
365
445
|
accentColor = '#8b5cf6',
|
|
366
446
|
onAddToCart,
|
|
447
|
+
viewportSize = 'large',
|
|
367
448
|
}: MessageBubbleProps) {
|
|
368
449
|
const isUser = message.role === 'user';
|
|
450
|
+
const isCompact = viewportSize === 'compact';
|
|
451
|
+
const isMedium = viewportSize === 'medium';
|
|
369
452
|
const [showSources, setShowSources] = React.useState(false);
|
|
370
453
|
const hasStructuredProductBlock = React.useMemo(
|
|
371
454
|
() => /```(?:ui|json|chart)\s*[\s\S]*?"(?:view|type)"\s*:\s*"(?:carousel|products)"/i.test(message.content),
|
|
@@ -548,6 +631,7 @@ export function MessageBubble({
|
|
|
548
631
|
accentColor={accentColor}
|
|
549
632
|
isStreaming={isStreaming}
|
|
550
633
|
onAddToCart={onAddToCart}
|
|
634
|
+
viewportSize={viewportSize}
|
|
551
635
|
/>
|
|
552
636
|
);
|
|
553
637
|
}
|
|
@@ -562,6 +646,7 @@ export function MessageBubble({
|
|
|
562
646
|
accentColor={accentColor}
|
|
563
647
|
isStreaming={isStreaming}
|
|
564
648
|
onAddToCart={onAddToCart}
|
|
649
|
+
viewportSize={viewportSize}
|
|
565
650
|
/>
|
|
566
651
|
);
|
|
567
652
|
}
|
|
@@ -587,27 +672,27 @@ export function MessageBubble({
|
|
|
587
672
|
);
|
|
588
673
|
},
|
|
589
674
|
}),
|
|
590
|
-
[primaryColor, accentColor, isStreaming, onAddToCart],
|
|
675
|
+
[primaryColor, accentColor, isStreaming, onAddToCart, viewportSize],
|
|
591
676
|
);
|
|
592
677
|
|
|
593
678
|
// ── Render ─────────────────────────────────────────────────────────────────
|
|
594
679
|
return (
|
|
595
|
-
<div className={`flex gap-3 ${isUser ? 'flex-row-reverse' : 'flex-row'} items-start`}>
|
|
680
|
+
<div className={`flex ${isCompact ? 'gap-2' : 'gap-3'} ${isUser ? 'flex-row-reverse' : 'flex-row'} items-start`}>
|
|
596
681
|
{/* Avatar */}
|
|
597
682
|
<div
|
|
598
|
-
className={`flex-shrink-0 w-8 h-8 rounded-full flex items-center justify-center shadow-lg ${isUser
|
|
683
|
+
className={`flex-shrink-0 ${isCompact ? 'w-7 h-7' : 'w-8 h-8'} rounded-full flex items-center justify-center shadow-lg ${isUser
|
|
599
684
|
? 'text-white'
|
|
600
685
|
: 'bg-slate-100 dark:bg-white/10 text-slate-700 dark:text-white/80'
|
|
601
686
|
}`}
|
|
602
687
|
style={isUser ? { background: `linear-gradient(135deg, ${primaryColor}, ${accentColor})` } : {}}
|
|
603
688
|
>
|
|
604
|
-
{isUser ? <User className=
|
|
689
|
+
{isUser ? <User className={`${isCompact ? 'w-3.5 h-3.5' : 'w-4 h-4'} text-white`} /> : <Bot className={`${isCompact ? 'w-3.5 h-3.5' : 'w-4 h-4'}`} />}
|
|
605
690
|
</div>
|
|
606
691
|
|
|
607
|
-
<div className={`flex flex-col gap-1 max-w-[90%] ${isUser ? 'items-end' : 'items-start'}`}>
|
|
692
|
+
<div className={`flex flex-col gap-1 ${isCompact ? 'max-w-[94%]' : isMedium ? 'max-w-[92%]' : 'max-w-[90%]'} ${isUser ? 'items-end' : 'items-start'}`}>
|
|
608
693
|
{/* Bubble */}
|
|
609
694
|
<div
|
|
610
|
-
className={`relative px-4 py-3 rounded-2xl
|
|
695
|
+
className={`relative ${isCompact ? 'px-3 py-2.5 text-[13px]' : 'px-4 py-3 text-sm'} rounded-2xl leading-relaxed shadow-sm dark:shadow-lg ${isUser
|
|
611
696
|
? 'text-white rounded-tr-sm'
|
|
612
697
|
: 'bg-white dark:bg-white/5 border border-slate-200 dark:border-white/10 text-slate-800 dark:text-white/90 rounded-tl-sm'
|
|
613
698
|
}`}
|
|
@@ -622,7 +707,7 @@ export function MessageBubble({
|
|
|
622
707
|
<span className="w-1.5 h-1.5 rounded-full bg-slate-400 dark:bg-white/60 animate-bounce [animation-delay:300ms]" />
|
|
623
708
|
</span>
|
|
624
709
|
) : (
|
|
625
|
-
<div className={`prose prose-sm max-w-none ${isUser ? 'prose-invert' : 'dark:prose-invert'}`}>
|
|
710
|
+
<div className={`prose ${isCompact ? 'prose-xs' : 'prose-sm'} max-w-none break-words ${isUser ? 'prose-invert' : 'dark:prose-invert'}`}>
|
|
626
711
|
<ReactMarkdown remarkPlugins={[remarkGfm]} components={markdownComponents}>
|
|
627
712
|
{processedMarkdown}
|
|
628
713
|
</ReactMarkdown>
|
|
@@ -44,7 +44,7 @@ export function ProductCarousel({ products, primaryColor = '#6366f1', onAddToCar
|
|
|
44
44
|
// Single product: No carousel needed
|
|
45
45
|
if (products.length === 1) {
|
|
46
46
|
return (
|
|
47
|
-
<div className="my-4 w-[
|
|
47
|
+
<div className="my-4 w-[min(88%,18rem)] min-w-0 max-w-full animate-fade-in-up">
|
|
48
48
|
<ProductCard product={products[0]} primaryColor={primaryColor} onAddToCart={onAddToCart} />
|
|
49
49
|
</div>
|
|
50
50
|
);
|
|
@@ -86,7 +86,7 @@ export function ProductCarousel({ products, primaryColor = '#6366f1', onAddToCar
|
|
|
86
86
|
{products.map((product) => (
|
|
87
87
|
<div
|
|
88
88
|
key={product.id}
|
|
89
|
-
className="snap-start flex-shrink-0 w-[
|
|
89
|
+
className="snap-start flex-shrink-0 w-[min(88%,18rem)] min-w-[11rem] max-w-full"
|
|
90
90
|
>
|
|
91
91
|
<ProductCard product={product} primaryColor={primaryColor} onAddToCart={onAddToCart} />
|
|
92
92
|
</div>
|
package/src/core/Pipeline.ts
CHANGED
|
@@ -138,6 +138,8 @@ When the user asks for a visual representation, comparison, distribution, breakd
|
|
|
138
138
|
- Never use ASCII art, markdown tables as the primary answer, or text-only fake charts when a UI block is requested.
|
|
139
139
|
- Put any short natural-language explanation before or after the \`\`\`ui\`\`\` block, but keep it concise.
|
|
140
140
|
- Return valid JSON inside the \`\`\`ui\`\`\` block.
|
|
141
|
+
- If the user explicitly asks for a pie chart, return "view": "chart" with "chartType": "pie", not a table fallback.
|
|
142
|
+
- Do not prefix the JSON with labels like "Table View", "Alternative", or explanatory text inside the code block.
|
|
141
143
|
|
|
142
144
|
5. EXAMPLE
|
|
143
145
|
User: "provide me the distribution of products across categories and highlight which ones are in stock in a pie chart"
|
package/src/types/props.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { Product, VectorMatch } from './index';
|
|
|
3
3
|
import { RagMessage } from './chat';
|
|
4
4
|
import { UIConfig } from '../config/RagConfig';
|
|
5
5
|
|
|
6
|
+
export type ChatViewportSize = 'compact' | 'medium' | 'large';
|
|
7
|
+
|
|
6
8
|
export interface ChatWindowProps {
|
|
7
9
|
/** Additional className for the wrapper div */
|
|
8
10
|
className?: string;
|
|
@@ -40,6 +42,7 @@ export interface MessageBubbleProps {
|
|
|
40
42
|
primaryColor: string;
|
|
41
43
|
accentColor: string;
|
|
42
44
|
onAddToCart?: (product: Product) => void;
|
|
45
|
+
viewportSize?: ChatViewportSize;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
export interface ProductCardProps {
|