@makolabs/ripple 0.4.1-0 → 0.5.0

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.
Files changed (59) hide show
  1. package/README.md +165 -205
  2. package/dist/adapters/ai/OpenAIAdapter.d.ts +115 -0
  3. package/dist/adapters/ai/OpenAIAdapter.js +568 -0
  4. package/dist/adapters/ai/index.d.ts +3 -0
  5. package/dist/adapters/ai/index.js +3 -0
  6. package/dist/adapters/ai/types.d.ts +108 -0
  7. package/dist/adapters/ai/types.js +31 -0
  8. package/dist/adapters/storage/BaseAdapter.js +31 -31
  9. package/dist/ai/AIChatInterface.svelte +435 -0
  10. package/dist/ai/AIChatInterface.svelte.d.ts +18 -0
  11. package/dist/ai/ChatInput.svelte +211 -0
  12. package/dist/ai/ChatInput.svelte.d.ts +18 -0
  13. package/dist/ai/CodeRenderer.svelte +174 -0
  14. package/dist/ai/CodeRenderer.svelte.d.ts +8 -0
  15. package/dist/ai/ComposeDropdown.svelte +171 -0
  16. package/dist/ai/ComposeDropdown.svelte.d.ts +9 -0
  17. package/dist/ai/MermaidRenderer.svelte +89 -0
  18. package/dist/ai/MermaidRenderer.svelte.d.ts +7 -0
  19. package/dist/ai/MessageBox.svelte +403 -0
  20. package/dist/ai/MessageBox.svelte.d.ts +12 -0
  21. package/dist/ai/ThinkingDisplay.svelte +275 -0
  22. package/dist/ai/ThinkingDisplay.svelte.d.ts +9 -0
  23. package/dist/ai/ai-chat-interface.d.ts +161 -0
  24. package/dist/ai/ai-chat-interface.js +63 -0
  25. package/dist/ai/content-detector.d.ts +41 -0
  26. package/dist/ai/content-detector.js +153 -0
  27. package/dist/config/ai.d.ts +13 -0
  28. package/dist/config/ai.js +43 -0
  29. package/dist/elements/accordion/accordion.js +1 -1
  30. package/dist/elements/badge/Badge.svelte +14 -3
  31. package/dist/elements/dropdown/Dropdown.svelte +2 -2
  32. package/dist/elements/dropdown/Select.svelte +1 -1
  33. package/dist/elements/progress/Progress.svelte +7 -10
  34. package/dist/file-browser/FileBrowser.svelte +1 -1
  35. package/dist/forms/DateRange.svelte +18 -16
  36. package/dist/forms/NumberInput.svelte +1 -1
  37. package/dist/forms/RadioInputs.svelte +1 -1
  38. package/dist/forms/RadioPill.svelte +1 -1
  39. package/dist/forms/Tags.svelte +2 -2
  40. package/dist/helper/date.d.ts +1 -0
  41. package/dist/helper/date.js +6 -0
  42. package/dist/index.d.ts +65 -1
  43. package/dist/index.js +11 -0
  44. package/dist/layout/activity-list/ActivityList.svelte +94 -0
  45. package/dist/layout/activity-list/ActivityList.svelte.d.ts +4 -0
  46. package/dist/layout/activity-list/activity-list.d.ts +152 -0
  47. package/dist/layout/activity-list/activity-list.js +59 -0
  48. package/dist/layout/card/Card.svelte +1 -5
  49. package/dist/layout/card/metric-card.d.ts +18 -18
  50. package/dist/layout/table/Cells.svelte +1 -7
  51. package/dist/layout/table/Cells.svelte.d.ts +1 -1
  52. package/dist/modal/Modal.svelte +4 -2
  53. package/dist/modal/Modal.svelte.d.ts +1 -1
  54. package/dist/modal/modal.d.ts +19 -18
  55. package/dist/modal/modal.js +7 -6
  56. package/dist/sonner/sonner.svelte +1 -7
  57. package/dist/types/markdown.d.ts +14 -0
  58. package/dist/utils/Portal.svelte +1 -1
  59. package/package.json +128 -121
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Error types for AI adapters
3
+ */
4
+ export class AIAdapterError extends Error {
5
+ code;
6
+ adapter;
7
+ constructor(message, code, adapter) {
8
+ super(message);
9
+ this.code = code;
10
+ this.adapter = adapter;
11
+ this.name = 'AIAdapterError';
12
+ }
13
+ }
14
+ export class AIConfigurationError extends AIAdapterError {
15
+ constructor(message, adapter) {
16
+ super(message, 'CONFIGURATION_ERROR', adapter);
17
+ this.name = 'AIConfigurationError';
18
+ }
19
+ }
20
+ export class AINetworkError extends AIAdapterError {
21
+ constructor(message, adapter) {
22
+ super(message, 'NETWORK_ERROR', adapter);
23
+ this.name = 'AINetworkError';
24
+ }
25
+ }
26
+ export class AIRateLimitError extends AIAdapterError {
27
+ constructor(message, adapter) {
28
+ super(message, 'RATE_LIMIT_ERROR', adapter);
29
+ this.name = 'AIRateLimitError';
30
+ }
31
+ }
@@ -87,7 +87,7 @@ export class BaseAdapter {
87
87
  }
88
88
  }
89
89
  // Count successes and failures
90
- const succeeded = individualResults.filter(r => r.success).length;
90
+ const succeeded = individualResults.filter((r) => r.success).length;
91
91
  const failed = individualResults.length - succeeded;
92
92
  // Return batch import result
93
93
  return {
@@ -98,7 +98,7 @@ export class BaseAdapter {
98
98
  succeeded,
99
99
  failed
100
100
  },
101
- results: individualResults.map(r => ({
101
+ results: individualResults.map((r) => ({
102
102
  key: r.fileId || '',
103
103
  success: r.success,
104
104
  fileId: r.fileId,
@@ -125,21 +125,21 @@ export class BaseAdapter {
125
125
  // Helper method to get detailed status
126
126
  getDetailedStatus(status) {
127
127
  const statusMap = {
128
- 'pending': 'Waiting to start',
129
- 'pending_import': 'Preparing import',
130
- 'initializing': 'Initializing import',
131
- 'pending_file_retrieval': 'Retrieving file',
132
- 'retrieving_file': 'Downloading file',
133
- 'file_retrieved': 'File downloaded',
134
- 'loading_file_contents_to_db': 'Loading data',
135
- 'file_contents_loaded': 'Data loaded',
136
- 'ready_to_process': 'Ready for processing',
137
- 'validating_source_file_rows': 'Validating file',
138
- 'converting_to_business_objects': 'Converting data',
139
- 'processing': 'Processing data',
140
- 'completed': 'Import completed',
141
- 'failed': 'Import failed',
142
- 'partially_processed': 'Partially processed'
128
+ pending: 'Waiting to start',
129
+ pending_import: 'Preparing import',
130
+ initializing: 'Initializing import',
131
+ pending_file_retrieval: 'Retrieving file',
132
+ retrieving_file: 'Downloading file',
133
+ file_retrieved: 'File downloaded',
134
+ loading_file_contents_to_db: 'Loading data',
135
+ file_contents_loaded: 'Data loaded',
136
+ ready_to_process: 'Ready for processing',
137
+ validating_source_file_rows: 'Validating file',
138
+ converting_to_business_objects: 'Converting data',
139
+ processing: 'Processing data',
140
+ completed: 'Import completed',
141
+ failed: 'Import failed',
142
+ partially_processed: 'Partially processed'
143
143
  };
144
144
  return statusMap[status] || status;
145
145
  }
@@ -151,20 +151,20 @@ export class BaseAdapter {
151
151
  }
152
152
  // Otherwise, use status-based progress estimates
153
153
  const progressMap = {
154
- 'pending': 5,
155
- 'pending_import': 10,
156
- 'initializing': 15,
157
- 'pending_file_retrieval': 20,
158
- 'retrieving_file': 30,
159
- 'file_retrieved': 40,
160
- 'loading_file_contents_to_db': 50,
161
- 'file_contents_loaded': 60,
162
- 'ready_to_process': 70,
163
- 'validating_source_file_rows': 80,
164
- 'converting_to_business_objects': 90,
165
- 'completed': 100,
166
- 'failed': 0,
167
- 'partially_processed': 95
154
+ pending: 5,
155
+ pending_import: 10,
156
+ initializing: 15,
157
+ pending_file_retrieval: 20,
158
+ retrieving_file: 30,
159
+ file_retrieved: 40,
160
+ loading_file_contents_to_db: 50,
161
+ file_contents_loaded: 60,
162
+ ready_to_process: 70,
163
+ validating_source_file_rows: 80,
164
+ converting_to_business_objects: 90,
165
+ completed: 100,
166
+ failed: 0,
167
+ partially_processed: 95
168
168
  };
169
169
  return progressMap[status] || 50;
170
170
  }
@@ -0,0 +1,435 @@
1
+ <script lang="ts">
2
+ import { cn } from '../helper/cls.js';
3
+ import { aiChatInterface } from './ai-chat-interface.js';
4
+ import MessageBox from './MessageBox.svelte';
5
+ import ChatInput from './ChatInput.svelte';
6
+ import ThinkingDisplay from './ThinkingDisplay.svelte';
7
+ import type { ChatMessage, ChatAction, VariantColors, StreamingCallback } from '../index.js';
8
+ import type { AIAdapter } from '../adapters/ai/index.js';
9
+
10
+ interface AIChatInterfaceProps {
11
+ adapter: AIAdapter;
12
+ title?: string;
13
+ subtitle?: string;
14
+ placeholder?: string;
15
+ color?: VariantColors;
16
+ disabled?: boolean;
17
+ loading?: boolean;
18
+ messages?: ChatMessage[];
19
+ class?: string;
20
+ context?: Record<string, unknown>;
21
+ showHeader?: boolean;
22
+ }
23
+
24
+ let {
25
+ adapter,
26
+ title = 'AI Assistant',
27
+ subtitle = 'How can I help you today?',
28
+ placeholder = 'Type your message...',
29
+ color = 'primary' as VariantColors,
30
+ disabled = false,
31
+ loading = false,
32
+ messages = $bindable([]),
33
+ class: className = '',
34
+ context = {},
35
+ showHeader = true
36
+ }: AIChatInterfaceProps = $props();
37
+
38
+ let userInput = $state('');
39
+ let isProcessing = $state(false);
40
+ let error = $state<string | null>(null);
41
+ let chatContainer: HTMLDivElement | undefined = $state();
42
+ let isAdapterConfigured = $state(false);
43
+ let textareaRef: HTMLTextAreaElement | undefined = $state();
44
+ let thinkingMode = $state(true);
45
+ let availableHeight = $state('100vh');
46
+
47
+ const { sendButton, background } = $derived(
48
+ aiChatInterface({
49
+ color: color as
50
+ | 'default'
51
+ | 'primary'
52
+ | 'secondary'
53
+ | 'info'
54
+ | 'success'
55
+ | 'warning'
56
+ | 'danger',
57
+ loading: loading || isProcessing,
58
+ disabled: disabled || !isAdapterConfigured
59
+ })
60
+ );
61
+
62
+ function generateId(): string {
63
+ return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
64
+ }
65
+
66
+ // Simple and reliable height calculation using native ResizeObserver
67
+ function findLayoutParent() {
68
+ if (!chatContainer) return null;
69
+
70
+ let parent = chatContainer.parentElement;
71
+ while (parent && parent !== document.body) {
72
+ const style = window.getComputedStyle(parent);
73
+ // Look for containers with explicit height or overflow control
74
+ if (style.height !== 'auto' || style.overflow !== 'visible' || style.position !== 'static') {
75
+ return parent;
76
+ }
77
+ parent = parent.parentElement;
78
+ }
79
+ return document.body;
80
+ }
81
+
82
+ function updateAvailableHeight() {
83
+ const layoutParent = findLayoutParent();
84
+ if (layoutParent) {
85
+ const rect = layoutParent.getBoundingClientRect();
86
+ availableHeight = `${Math.max(rect.height, 300)}px`;
87
+ } else {
88
+ // Fallback: use full viewport since we couldn't find a layout parent
89
+ // This means the chat is likely the main content
90
+ availableHeight = `${Math.max(window.innerHeight, 300)}px`;
91
+ }
92
+ }
93
+
94
+ // Use ResizeObserver for efficient and accurate size tracking
95
+ $effect(() => {
96
+ if (typeof window !== 'undefined' && chatContainer) {
97
+ // Initial calculation
98
+ updateAvailableHeight();
99
+
100
+ // Set up ResizeObserver for the layout parent
101
+ const layoutParent = findLayoutParent();
102
+ if (layoutParent && 'ResizeObserver' in window) {
103
+ const resizeObserver = new ResizeObserver(() => {
104
+ updateAvailableHeight();
105
+ });
106
+
107
+ resizeObserver.observe(layoutParent);
108
+
109
+ // Also observe viewport changes
110
+ const handleResize = () => updateAvailableHeight();
111
+ window.addEventListener('resize', handleResize);
112
+
113
+ return () => {
114
+ resizeObserver.disconnect();
115
+ window.removeEventListener('resize', handleResize);
116
+ };
117
+ } else {
118
+ // Fallback for browsers without ResizeObserver
119
+ const handleResize = () => updateAvailableHeight();
120
+ window.addEventListener('resize', handleResize);
121
+
122
+ return () => {
123
+ window.removeEventListener('resize', handleResize);
124
+ };
125
+ }
126
+ }
127
+ });
128
+
129
+ // Container classes for the main layout - use calculated height
130
+ const containerClasses = $derived(
131
+ cn(
132
+ 'w-full flex flex-col',
133
+ messages.length === 0
134
+ ? 'mx-auto max-w-4xl items-center justify-center px-6'
135
+ : 'overflow-hidden',
136
+ messages.length > 0 && background,
137
+ className
138
+ )
139
+ );
140
+
141
+
142
+
143
+ function addMessage(
144
+ type: 'chat' | 'action' | 'thinking',
145
+ content: string,
146
+ action?: ChatAction,
147
+ messageId?: string,
148
+ thinkingContent?: string,
149
+ isThinkingComplete?: boolean
150
+ ): ChatMessage {
151
+ const message: ChatMessage = {
152
+ id: messageId || generateId(),
153
+ type,
154
+ content,
155
+ timestamp: new Date(),
156
+ action,
157
+ thinkingContent,
158
+ isThinkingComplete
159
+ };
160
+
161
+ messages = [...messages, message];
162
+
163
+ return message;
164
+ }
165
+
166
+ function updateMessageById(messageId: string, content: string, thinkingContent?: string, isThinkingComplete?: boolean): void {
167
+ messages = messages.map((msg) =>
168
+ msg.id === messageId
169
+ ? {
170
+ ...msg,
171
+ content,
172
+ ...(thinkingContent !== undefined && { thinkingContent }),
173
+ ...(isThinkingComplete !== undefined && { isThinkingComplete })
174
+ }
175
+ : msg
176
+ );
177
+ }
178
+
179
+ async function handleSubmit() {
180
+ if (!userInput.trim() || isProcessing || disabled || !isAdapterConfigured) return;
181
+
182
+ const input = userInput.trim();
183
+ userInput = '';
184
+ error = null;
185
+ isProcessing = true;
186
+
187
+ try {
188
+ // Add user message with proper prefix
189
+ addMessage('chat', `User: ${input}`);
190
+
191
+ // Check if adapter supports streaming and use it
192
+ if (adapter.sendMessageStream) {
193
+ // Create streaming callback
194
+ const onStream: StreamingCallback = (response) => {
195
+ if (response.messageId) {
196
+ // Check if message exists, if not create it
197
+ const existingMessage = messages.find((msg) => msg.id === response.messageId);
198
+
199
+ if (!existingMessage) {
200
+ // Only create new streaming message if there's content or thinking content
201
+ if (response.content || response.thinkingContent) {
202
+ addMessage(
203
+ response.type,
204
+ response.content,
205
+ response.action,
206
+ response.messageId,
207
+ response.thinkingContent,
208
+ response.isThinkingComplete
209
+ );
210
+ }
211
+ } else {
212
+ // Update existing message
213
+ updateMessageById(
214
+ response.messageId,
215
+ response.content,
216
+ response.thinkingContent,
217
+ response.isThinkingComplete
218
+ );
219
+ }
220
+ }
221
+ };
222
+
223
+ // Send with streaming (include thinking mode context)
224
+ const contextWithThinking = { ...context, thinkingMode } as Record<string, unknown>;
225
+ await adapter.sendMessageStream(input, onStream, contextWithThinking);
226
+ } else {
227
+ // Fallback to regular sendMessage
228
+ const contextWithThinking = { ...context, thinkingMode } as Record<string, unknown>;
229
+ const response = await adapter.sendMessage(input, contextWithThinking);
230
+ addMessage(
231
+ response.type,
232
+ response.content,
233
+ response.action,
234
+ undefined,
235
+ response.thinkingContent,
236
+ response.isThinkingComplete
237
+ );
238
+ }
239
+ } catch (err) {
240
+ console.error('AI request failed:', err);
241
+
242
+ let errorMessage = 'Something went wrong. Please try again.';
243
+
244
+ if (err instanceof Error) {
245
+ errorMessage = err.message;
246
+ }
247
+
248
+ addMessage('chat', `Sorry, ${errorMessage}`);
249
+
250
+ error = errorMessage;
251
+ setTimeout(() => {
252
+ error = null;
253
+ }, 5000);
254
+ } finally {
255
+ isProcessing = false;
256
+
257
+ // Auto-focus the input after response is complete
258
+ setTimeout(() => {
259
+ textareaRef?.focus();
260
+ }, 100);
261
+ }
262
+ }
263
+
264
+ function handleKeyDown(event: KeyboardEvent) {
265
+ if (event.key === 'Enter' && !event.shiftKey) {
266
+ event.preventDefault();
267
+ handleSubmit();
268
+ }
269
+ }
270
+
271
+ function handleThinkingToggle(enabled: boolean) {
272
+ thinkingMode = enabled;
273
+ // You can add additional logic here when thinking mode changes
274
+ console.log('Thinking mode:', enabled ? 'enabled' : 'disabled');
275
+ }
276
+
277
+
278
+
279
+ // Check adapter configuration
280
+ $effect(() => {
281
+ if (adapter) {
282
+ isAdapterConfigured = adapter.isConfigured();
283
+
284
+ // Load existing history if available
285
+ if (adapter.getHistory && messages.length === 0) {
286
+ const history = adapter.getHistory();
287
+ if (history.length > 0) {
288
+ messages = history;
289
+ }
290
+ }
291
+ } else {
292
+ isAdapterConfigured = false;
293
+ }
294
+ });
295
+
296
+ // Simple auto-scroll to bottom
297
+ $effect(() => {
298
+ if (chatContainer && messages.length > 0) {
299
+ setTimeout(() => {
300
+ chatContainer?.scrollTo({ top: chatContainer.scrollHeight, behavior: 'smooth' });
301
+ }, 100);
302
+ }
303
+ });
304
+
305
+ </script>
306
+
307
+ <!-- Unified Layout Container -->
308
+ <div class={containerClasses} bind:this={chatContainer} style="height: {availableHeight}">
309
+ <!-- Empty State Content (only shown when no messages) -->
310
+ {#if messages.length === 0}
311
+ <!-- Configuration Error -->
312
+ {#if !isAdapterConfigured}
313
+ <div class="mb-8 w-full max-w-2xl rounded-xl border border-amber-200 bg-amber-50 px-6 py-4">
314
+ <div class="flex items-center gap-3">
315
+ <div class="flex h-10 w-10 items-center justify-center rounded-full bg-amber-100">
316
+ <svg
317
+ class="h-5 w-5 text-amber-600"
318
+ fill="none"
319
+ stroke="currentColor"
320
+ viewBox="0 0 24 24"
321
+ >
322
+ <path
323
+ stroke-linecap="round"
324
+ stroke-linejoin="round"
325
+ stroke-width="2"
326
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16c-.77.833.192 2.5 1.732 2.5z"
327
+ />
328
+ </svg>
329
+ </div>
330
+ <div>
331
+ <h3 class="font-medium text-amber-900">Configuration Required</h3>
332
+ <p class="text-sm text-amber-700">
333
+ Please configure your AI adapter to start chatting.
334
+ </p>
335
+ </div>
336
+ </div>
337
+ </div>
338
+ {/if}
339
+
340
+ <!-- Centered Content -->
341
+ <div class="mb-8 text-center">
342
+ <h1 class="mb-8 text-4xl font-medium text-gray-900">{title}</h1>
343
+ {#if subtitle}
344
+ <p class="mb-6 text-lg text-gray-600">{subtitle}</p>
345
+ {/if}
346
+ </div>
347
+ {:else}
348
+ <!-- Chat Layout Header -->
349
+ <div
350
+ class="sticky top-0 z-10 flex flex-shrink-0 items-center justify-between border-b border-gray-200 bg-white/50 px-6 py-3 backdrop-blur-sm"
351
+ >
352
+ <h1 class="text-sm font-medium text-gray-900">{title}</h1>
353
+ <div class="flex items-center gap-2">
354
+ {#if isAdapterConfigured}
355
+ <div
356
+ class="flex items-center gap-2 rounded-full bg-emerald-100/50 px-2 py-1 text-xs font-medium text-emerald-700"
357
+ >
358
+ <div class="h-1.5 w-1.5 rounded-full bg-emerald-500"></div>
359
+ Online
360
+ </div>
361
+ {:else}
362
+ <div
363
+ class="flex items-center gap-2 rounded-full bg-gray-100/50 px-2 py-1 text-xs font-medium text-gray-500"
364
+ >
365
+ <div class="h-1.5 w-1.5 rounded-full bg-gray-400"></div>
366
+ Offline
367
+ </div>
368
+ {/if}
369
+ </div>
370
+ </div>
371
+
372
+ <!-- Chat Messages Area -->
373
+ <main class="flex flex-1 flex-col overflow-y-auto">
374
+ <div class="mx-auto w-full max-w-4xl space-y-4 px-6 py-4 flex-1">
375
+ {#each messages as message (message.id)}
376
+ {@const isUser = message.content.startsWith('User:')}
377
+ {@const displayContent = isUser ? message.content.replace('User: ', '') : message.content}
378
+
379
+ <!-- Show thinking display for AI messages when thinking mode is enabled -->
380
+ {#if !isUser && message.thinkingContent}
381
+ <ThinkingDisplay
382
+ content={message.thinkingContent}
383
+ isComplete={message.isThinkingComplete || false}
384
+ class="mb-2"
385
+ />
386
+ {/if}
387
+
388
+ <!-- Only show message if it has content -->
389
+ {#if displayContent.trim()}
390
+ <div class={cn('mb-4 flex w-full', isUser ? 'justify-end' : 'justify-start')}>
391
+ <MessageBox content={displayContent} {isUser} {color} timestamp={message.timestamp} />
392
+ </div>
393
+ {/if}
394
+ {/each}
395
+
396
+ <!-- Typing Indicator -->
397
+ {#if isProcessing}
398
+ <div class="flex w-full justify-start">
399
+ <div
400
+ class="rounded-md border border-gray-200 bg-white/80 px-4 py-3 shadow-sm backdrop-blur-sm"
401
+ >
402
+ <div class="flex items-center space-x-1">
403
+ <div class="h-2 w-2 animate-bounce rounded-full bg-gray-400"></div>
404
+ <div
405
+ class="h-2 w-2 animate-bounce rounded-full bg-gray-400"
406
+ style="animation-delay: 0.1s"
407
+ ></div>
408
+ <div
409
+ class="h-2 w-2 animate-bounce rounded-full bg-gray-400"
410
+ style="animation-delay: 0.2s"
411
+ ></div>
412
+ </div>
413
+ </div>
414
+ </div>
415
+ {/if}
416
+ </div>
417
+ </main>
418
+ {/if}
419
+
420
+ <!-- Single Input Area (used by both layouts) -->
421
+ <ChatInput
422
+ bind:userInput
423
+ bind:textareaRef
424
+ bind:thinkingMode
425
+ placeholder={isAdapterConfigured ? placeholder : 'Configure AI adapter to start chatting...'}
426
+ {isProcessing}
427
+ {disabled}
428
+ {isAdapterConfigured}
429
+ {color}
430
+ hasMessages={messages.length > 0}
431
+ onSubmit={handleSubmit}
432
+ onKeyDown={handleKeyDown}
433
+ onThinkingToggle={handleThinkingToggle}
434
+ />
435
+ </div>
@@ -0,0 +1,18 @@
1
+ import type { ChatMessage, VariantColors } from '../index.js';
2
+ import type { AIAdapter } from '../adapters/ai/index.js';
3
+ interface AIChatInterfaceProps {
4
+ adapter: AIAdapter;
5
+ title?: string;
6
+ subtitle?: string;
7
+ placeholder?: string;
8
+ color?: VariantColors;
9
+ disabled?: boolean;
10
+ loading?: boolean;
11
+ messages?: ChatMessage[];
12
+ class?: string;
13
+ context?: Record<string, unknown>;
14
+ showHeader?: boolean;
15
+ }
16
+ declare const AiChatInterface: import("svelte").Component<AIChatInterfaceProps, {}, "messages">;
17
+ type AiChatInterface = ReturnType<typeof AiChatInterface>;
18
+ export default AiChatInterface;