@doderasoftware/restify-ai 0.2.0-beta.1 โ†’ 0.2.0-beta.3

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 (48) hide show
  1. package/README.md +445 -31
  2. package/dist/components/AiChatDrawer.vue.d.ts +25 -3
  3. package/dist/components/AiChatDrawer.vue.d.ts.map +1 -1
  4. package/dist/components/ChatInput.vue.d.ts +10 -0
  5. package/dist/components/ChatInput.vue.d.ts.map +1 -1
  6. package/dist/components/ChatMessage.vue.d.ts.map +1 -1
  7. package/dist/components/drawer/ConversationHistory.vue.d.ts +3 -0
  8. package/dist/components/drawer/ConversationHistory.vue.d.ts.map +1 -0
  9. package/dist/components/drawer/DrawerHeader.vue.d.ts +4 -0
  10. package/dist/components/drawer/DrawerHeader.vue.d.ts.map +1 -1
  11. package/dist/components/drawer/DrawerMessageList.vue.d.ts.map +1 -1
  12. package/dist/components/icons/IconHistory.vue.d.ts +3 -0
  13. package/dist/components/icons/IconHistory.vue.d.ts.map +1 -0
  14. package/dist/components/icons/IconMicrophone.vue.d.ts +3 -0
  15. package/dist/components/icons/IconMicrophone.vue.d.ts.map +1 -0
  16. package/dist/components/icons/IconMicrophoneOff.vue.d.ts +3 -0
  17. package/dist/components/icons/IconMicrophoneOff.vue.d.ts.map +1 -0
  18. package/dist/components/icons/index.d.ts +3 -0
  19. package/dist/components/icons/index.d.ts.map +1 -1
  20. package/dist/components/input/AudioWave.vue.d.ts +29 -0
  21. package/dist/components/input/AudioWave.vue.d.ts.map +1 -0
  22. package/dist/components/input/InputActions.vue.d.ts +24 -3
  23. package/dist/components/input/InputActions.vue.d.ts.map +1 -1
  24. package/dist/composables/useChatInput.d.ts +2 -0
  25. package/dist/composables/useChatInput.d.ts.map +1 -1
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/index.d.ts +5 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/restify-ai.js +2965 -2391
  30. package/dist/restify-ai.umd.cjs +52 -52
  31. package/dist/store/storage.d.ts +10 -1
  32. package/dist/store/storage.d.ts.map +1 -1
  33. package/dist/store/store.d.ts +42 -0
  34. package/dist/store/store.d.ts.map +1 -1
  35. package/dist/style.css +1 -1
  36. package/dist/types/api.d.ts.map +1 -1
  37. package/dist/types/chat.d.ts +12 -0
  38. package/dist/types/chat.d.ts.map +1 -1
  39. package/dist/types/config.d.ts +28 -1
  40. package/dist/types/config.d.ts.map +1 -1
  41. package/dist/types/index.d.ts +2 -2
  42. package/dist/types/index.d.ts.map +1 -1
  43. package/dist/types/texts.d.ts +8 -0
  44. package/dist/types/texts.d.ts.map +1 -1
  45. package/dist/types/ui.d.ts +11 -3
  46. package/dist/types/ui.d.ts.map +1 -1
  47. package/package.json +10 -8
  48. package/tailwind.config.cjs +1 -30
package/README.md CHANGED
@@ -15,6 +15,7 @@ A production-ready AI chatbot component for Vue 3 with real-time SSE streaming,
15
15
 
16
16
  - ๐ŸŒŠ **Real-time SSE Streaming** - Smooth character-by-character response streaming
17
17
  - ๐Ÿ“Ž **File Attachments** - Upload and process documents, images, and more
18
+ - ๐ŸŽค **Audio Input** - Voice recording with visual feedback and wave animation
18
19
  - ๐Ÿ‘ฅ **@Mentions System** - Reference entities from your application (employees, jobs, projects, etc.)
19
20
  - ๐Ÿ’ก **Context-Aware Suggestions** - Smart prompts based on current page/route
20
21
  - ๐Ÿ’ฌ **Chat History** - Persistent conversation memory with configurable limits
@@ -251,10 +252,13 @@ export function setupRestifyAi(app: App) {
251
252
  },
252
253
 
253
254
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
254
- // LIMITS
255
+ // LIMITS & AI MODEL
255
256
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
256
257
 
257
258
  chatHistoryLimit: 20, // Maximum user messages per conversation
259
+ model: 'gpt-4', // AI model to use (passed to backend)
260
+ temperature: 0.7, // AI temperature (0-1)
261
+ maxTokens: 2048, // Maximum tokens per response
258
262
  maxAttachments: 5,
259
263
  maxFileSize: 10 * 1024 * 1024, // 10MB
260
264
  acceptedFileTypes: 'image/*,.pdf,.txt,.doc,.docx,.xls,.xlsx,.csv',
@@ -272,6 +276,11 @@ export function setupRestifyAi(app: App) {
272
276
 
273
277
  keyboardShortcut: 'mod+g', // 'mod' = Cmd on Mac, Ctrl on Windows
274
278
  enableSupportMode: true,
279
+ useQuota: true, // Enable quota management
280
+ useHeadersRateLimiter: true, // Use rate limit headers instead of quota endpoint
281
+ useConversationId: true, // Enable conversation ID tracking
282
+ useConversationHistory: true, // Enable conversation history sidebar
283
+ maxConversationHistory: 10, // Max conversations to store (default: 10)
275
284
  canToggle: () => true,
276
285
 
277
286
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
@@ -291,6 +300,7 @@ export function setupRestifyAi(app: App) {
291
300
  onResponseReceived: (message) => console.log('Response:', message),
292
301
  onDrawerToggle: (isOpen) => console.log('Drawer:', isOpen),
293
302
  onNewChat: () => console.log('New chat started'),
303
+ onSetupComplete: () => console.log('Setup completed'),
294
304
 
295
305
  // Stream lifecycle hooks
296
306
  onStreamStart: () => console.log('Stream started'),
@@ -318,7 +328,7 @@ export function setupRestifyAi(app: App) {
318
328
  | `topOffset` | `string` | `"0"` | Top offset for fixed headers |
319
329
  | `position` | `"left" \| "right"` | `"right"` | Drawer position |
320
330
  | `showBackdrop` | `boolean` | `false` | Show backdrop overlay |
321
- | `closeOnBackdropClick` | `boolean` | `false` | Close when clicking backdrop |
331
+ | `closeOnBackdropClick` | `boolean` | `true` | Close when clicking backdrop |
322
332
  | `closeOnEscape` | `boolean` | `true` | Close on Escape key |
323
333
  | `showQuota` | `boolean` | `true` | Show quota display (API usage remaining) |
324
334
  | `showMessageCount` | `boolean` | `true` | Show message count badge (X/20 format) |
@@ -327,6 +337,9 @@ export function setupRestifyAi(app: App) {
327
337
  | `showCloseButton` | `boolean` | `true` | Show close button |
328
338
  | `showNewChatButton` | `boolean` | `true` | Show new chat button |
329
339
  | `confirmClose` | `boolean` | `true` | Confirm before clearing history |
340
+ | `enableAudioInput` | `boolean` | `false` | Enable voice recording button |
341
+ | `isRecording` | `boolean` | `false` | Audio recording state (controlled) |
342
+ | `inputValue` | `string` | `''` | Input text value (v-model:inputValue) |
330
343
  | `autoFetchQuota` | `boolean` | `true` | Auto-fetch quota when opened |
331
344
  | `historyLimit` | `HistoryLimitConfig` | - | History limit configuration |
332
345
  | `loadingText` | `LoadingTextConfig` | - | Loading text configuration |
@@ -369,14 +382,84 @@ function handleContactSupport() {
369
382
  </script>
370
383
  ```
371
384
 
385
+ ### Audio Input Example
386
+
387
+ Enable voice recording with the `enableAudioInput` prop and handle the recording state:
388
+
389
+ ```vue
390
+ <template>
391
+ <AiChatDrawer
392
+ v-model="aiStore.showChat"
393
+ v-model:input-value="audioInput"
394
+ :enable-audio-input="true"
395
+ :is-recording="isRecording"
396
+ @toggle-audio-recording="toggleRecording"
397
+ />
398
+ </template>
399
+
400
+ <script setup lang="ts">
401
+ import { ref } from 'vue'
402
+ import { AiChatDrawer, useRestifyAiStore } from '@doderasoftware/restify-ai'
403
+
404
+ const aiStore = useRestifyAiStore()
405
+ const isRecording = ref(false)
406
+ const audioInput = ref('')
407
+ let mediaRecorder: MediaRecorder | null = null
408
+
409
+ async function toggleRecording() {
410
+ if (isRecording.value) {
411
+ // Stop recording
412
+ mediaRecorder?.stop()
413
+ isRecording.value = false
414
+ } else {
415
+ // Start recording
416
+ try {
417
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
418
+ mediaRecorder = new MediaRecorder(stream)
419
+
420
+ const chunks: Blob[] = []
421
+ mediaRecorder.ondataavailable = (e) => chunks.push(e.data)
422
+ mediaRecorder.onstop = async () => {
423
+ const audioBlob = new Blob(chunks, { type: 'audio/webm' })
424
+ // Process the audio (e.g., send to transcription API)
425
+ const transcription = await transcribeAudio(audioBlob)
426
+ audioInput.value = transcription
427
+ stream.getTracks().forEach(track => track.stop())
428
+ }
429
+
430
+ mediaRecorder.start()
431
+ isRecording.value = true
432
+ } catch (error) {
433
+ console.error('Failed to start recording:', error)
434
+ }
435
+ }
436
+ }
437
+
438
+ async function transcribeAudio(blob: Blob): Promise<string> {
439
+ // Implement your transcription logic here
440
+ // e.g., send to OpenAI Whisper, Google Speech-to-Text, etc.
441
+ return 'Transcribed text...'
442
+ }
443
+ </script>
444
+ ```
445
+
446
+ **Features:**
447
+ - ๐ŸŽค Microphone button appears when `enableAudioInput` is enabled
448
+ - ๐Ÿ“Š Animated wave indicator shows when recording is active
449
+ - ๐Ÿ”ด Visual feedback with red styling during recording
450
+ - ๐ŸŽจ Customizable via `audioButton`, `audioButtonRecording`, and `audioRecordingIndicator` UI classes
451
+ - ๐ŸŒ Text labels customizable via `startRecording`, `stopRecording`, and `recording` texts
452
+
372
453
  ## ๐Ÿ“ก Events
373
454
 
374
455
  | Event | Payload | Description |
375
456
  |-------|---------|-------------|
376
457
  | `update:modelValue` | `boolean` | Drawer state changed |
458
+ | `update:inputValue` | `string` | Input text value changed |
377
459
  | `close` | - | Drawer was closed |
378
460
  | `contact-support` | - | Support mode activated |
379
461
  | `new-chat` | - | New chat started |
462
+ | `toggle-audio-recording` | - | Audio recording toggled |
380
463
 
381
464
  ## ๐ŸŽฐ Slots
382
465
 
@@ -385,7 +468,7 @@ function handleContactSupport() {
385
468
  | `header` | `HeaderSlotProps` | Custom header content |
386
469
  | `quota` | `{ quota: ChatQuota }` | Custom quota display |
387
470
  | `setup` | - | Custom setup guide |
388
- | `empty-state` | `{ suggestions, onClick }` | Custom empty state |
471
+ | `empty-state` | `EmptyStateSlotProps` | Custom empty state |
389
472
  | `message` | `MessageSlotProps` | Custom message bubble |
390
473
  | `input` | `InputSlotProps` | Custom input area |
391
474
  | `context-link` | - | Custom context link below input |
@@ -403,6 +486,11 @@ interface HeaderSlotProps {
403
486
  onToggleFullscreen: () => void
404
487
  }
405
488
 
489
+ interface EmptyStateSlotProps {
490
+ suggestions: AISuggestion[]
491
+ onSuggestionClick: (suggestion: AISuggestion) => void
492
+ }
493
+
406
494
  interface MessageSlotProps {
407
495
  message: ChatMessage
408
496
  isUser: boolean
@@ -430,15 +518,22 @@ const store = useRestifyAiStore()
430
518
  // STATE
431
519
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
432
520
 
521
+ store.chatHistoryLimit // number - Maximum messages allowed
433
522
  store.chatHistory // ChatMessage[] - All messages
523
+ store.uploadedFiles // Record<string, ChatAttachment> - Uploaded files by ID
434
524
  store.showChat // boolean - Drawer visibility
435
525
  store.sending // boolean - Message being sent
436
526
  store.loading // boolean - Loading state
437
527
  store.isFullscreen // boolean - Fullscreen mode
438
528
  store.quota // { limit, used, remaining }
439
- store.error // { message, failedQuestion, failedAttachments, timestamp }
529
+ store.error // { message, failedQuestion, failedAttachments, timestamp, quotaExceeded }
440
530
  store.supportRequestMode // boolean - Support mode active
441
531
  store.pageContext // PageContext | null - Current page context
532
+ store.setupState // SetupState - Setup wizard state
533
+ store.conversationId // string | null - Current conversation ID from backend
534
+ store.conversationName // string | null - Current conversation name
535
+ store.conversationHistory // ConversationHistoryItem[] - List of saved conversations
536
+ store.showHistorySidebar // boolean - History sidebar visibility
442
537
 
443
538
  // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
444
539
  // GETTERS
@@ -464,7 +559,21 @@ store.toggleSupportMode() // Toggle support mode
464
559
  store.fetchQuota() // Fetch quota from server
465
560
  store.uploadFile(file) // Upload file
466
561
  store.setPageContext(context) // Set page context
467
- store.scrollToBottom() // Scroll chat to bottom
562
+ store.scrollToBottom(delay?) // Scroll chat to bottom
563
+
564
+ // Conversation History Actions
565
+ store.toggleHistorySidebar() // Toggle history sidebar
566
+ store.loadConversation(id) // Load a saved conversation
567
+ store.renameConversation(id, title) // Rename a conversation
568
+ store.deleteConversation(id) // Delete a saved conversation
569
+ store.saveCurrentConversation() // Save current conversation
570
+
571
+ // Setup Mode Actions
572
+ store.startSetupMode() // Start setup wizard
573
+ store.setSetupStep(step) // Set current setup step
574
+ store.testConnection() // Test backend connection
575
+ store.completeSetup() // Complete setup
576
+ store.skipSetup() // Skip setup wizard
468
577
  ```
469
578
 
470
579
  ## ๐Ÿช Composables
@@ -521,7 +630,44 @@ Get suggestions for current context:
521
630
  ```typescript
522
631
  import { useAiSuggestions } from '@doderasoftware/restify-ai'
523
632
 
524
- const { suggestions, resolvePrompt } = useAiSuggestions()
633
+ const { suggestions, hasContextualSuggestions, resolvePrompt } = useAiSuggestions()
634
+ ```
635
+
636
+ ### useLoadingText
637
+
638
+ Manage dynamic loading text messages:
639
+
640
+ ```typescript
641
+ import { useLoadingText } from '@doderasoftware/restify-ai'
642
+
643
+ const {
644
+ loadingMessage,
645
+ startLoadingText,
646
+ resetLoadingText
647
+ } = useLoadingText(
648
+ () => isSending.value,
649
+ () => ({
650
+ messages: ['Thinking...', 'Analyzing...', 'Crafting response...'],
651
+ intervals: [0, 2000, 5000]
652
+ })
653
+ )
654
+ ```
655
+
656
+ ### useHistoryLimit
657
+
658
+ Handle chat history limits with warnings:
659
+
660
+ ```typescript
661
+ import { useHistoryLimit } from '@doderasoftware/restify-ai'
662
+
663
+ const historyLimit = useHistoryLimit({
664
+ getHistoryLength: () => chatHistory.length,
665
+ getStoreLimit: () => store.chatHistoryLimit,
666
+ getConfig: () => historyLimitConfig,
667
+ getTexts: () => texts,
668
+ onStartNewChat: () => store.clearChatHistory(),
669
+ onNewChatEmit: () => emit('new-chat'),
670
+ })
525
671
  ```
526
672
 
527
673
  ## ๐Ÿท๏ธ Mention Providers
@@ -757,26 +903,41 @@ interface AISuggestion {
757
903
 
758
904
  ## ๐ŸŽจ UI Customization
759
905
 
760
- Override CSS classes for any component:
906
+ Override CSS classes for any component. The `ui` prop on `AiChatDrawer` allows you to customize all components in one place - it extends all child component UI interfaces, so you can customize the drawer, input, messages, empty state, and mentions all from a single object.
761
907
 
762
908
  ```vue
763
909
  <AiChatDrawer
764
910
  v-model="isOpen"
765
911
  :ui="{
912
+ // Drawer customization
766
913
  backdrop: 'bg-black/50 backdrop-blur-sm',
767
914
  drawer: 'shadow-2xl',
768
915
  panel: 'bg-gray-50 dark:bg-gray-900',
769
916
  header: 'border-b-2 border-primary-500',
770
917
  body: 'custom-scrollbar',
771
918
  footer: 'border-t border-gray-200',
919
+
920
+ // ChatInput customization (automatically passed down)
921
+ textarea: 'rounded-xl',
922
+ sendButton: 'bg-blue-500 hover:bg-blue-600',
923
+
924
+ // ChatMessage customization (automatically passed down)
925
+ userBubble: 'bg-blue-500 text-white',
926
+ assistantBubble: 'bg-gray-100 dark:bg-gray-800',
927
+
928
+ // AiEmptyState customization (automatically passed down)
929
+ suggestionCard: 'border-2 border-primary-500',
772
930
  }"
773
931
  />
774
932
  ```
775
933
 
776
934
  ### AiChatDrawerUI
777
935
 
936
+ The main UI interface that combines all component UI interfaces. Pass this to the `ui` prop to customize all components:
937
+
778
938
  ```typescript
779
- interface AiChatDrawerUI {
939
+ interface AiChatDrawerUI extends ChatInputUI, ChatMessageUI, AiEmptyStateUI, MentionListUI {
940
+ // Drawer-specific
780
941
  backdrop?: string // Backdrop overlay
781
942
  drawer?: string // Main drawer container
782
943
  panel?: string // Inner panel
@@ -786,17 +947,24 @@ interface AiChatDrawerUI {
786
947
  headerActionButton?: string // Header buttons
787
948
  body?: string // Messages container
788
949
  footer?: string // Footer container
950
+
951
+ // Dialogs
952
+ closeConfirmModal?: string // Confirm modal
953
+ closeConfirmButton?: string // Confirm button
954
+ cancelButton?: string // Cancel button
955
+ historyLimitModal?: string // History limit modal
956
+ historyLimitButton?: string // History limit button
957
+
958
+ // Header elements
789
959
  quotaDisplay?: string // Quota display
790
960
  messageCountBadge?: string // Message count badge
791
961
  newChatButton?: string // New chat button
962
+
963
+ // Error display
792
964
  errorContainer?: string // Error container
793
965
  errorMessage?: string // Error message
794
966
  retryButton?: string // Retry button
795
- closeConfirmModal?: string // Confirm modal
796
- closeConfirmButton?: string // Confirm button
797
- cancelButton?: string // Cancel button
798
- historyLimitModal?: string // History limit modal
799
- historyLimitButton?: string // History limit button
967
+ contactSupportButton?: string // Contact support button
800
968
  }
801
969
  ```
802
970
 
@@ -824,6 +992,10 @@ interface ChatInputUI {
824
992
  suggestionItem?: string // Suggestion item
825
993
  suggestionItemSelected?: string // Selected suggestion
826
994
  contextLink?: string // Context link
995
+ // Audio input
996
+ audioButton?: string // Audio button
997
+ audioButtonRecording?: string // Audio button when recording
998
+ audioRecordingIndicator?: string // Recording indicator
827
999
  }
828
1000
  ```
829
1001
 
@@ -847,6 +1019,66 @@ interface ChatMessageUI {
847
1019
  }
848
1020
  ```
849
1021
 
1022
+ ### AiEmptyStateUI
1023
+
1024
+ ```typescript
1025
+ interface AiEmptyStateUI {
1026
+ root?: string // Root container
1027
+ content?: string // Content container
1028
+ header?: string // Header container
1029
+ badge?: string // AI badge
1030
+ title?: string // Title
1031
+ description?: string // Description
1032
+ grid?: string // Suggestions grid
1033
+ suggestionCard?: string // Suggestion card
1034
+ suggestionIconContainer?: string // Icon container
1035
+ suggestionIcon?: string // Icon
1036
+ suggestionTitle?: string // Suggestion title
1037
+ suggestionDescription?: string // Suggestion description
1038
+ }
1039
+ ```
1040
+
1041
+ ### MentionListUI
1042
+
1043
+ ```typescript
1044
+ interface MentionListUI {
1045
+ root?: string // Root container
1046
+ container?: string // List container
1047
+ groupHeader?: string // Group header
1048
+ item?: string // Item
1049
+ itemSelected?: string // Selected item
1050
+ itemIcon?: string // Item icon
1051
+ itemContent?: string // Item content
1052
+ itemName?: string // Item name
1053
+ itemSubtitle?: string // Item subtitle
1054
+ }
1055
+ ```
1056
+
1057
+ ### AiAvatarUI / UserAvatarUI
1058
+
1059
+ ```typescript
1060
+ interface AiAvatarUI {
1061
+ container?: string // Container
1062
+ icon?: string // Icon
1063
+ }
1064
+
1065
+ interface UserAvatarUI {
1066
+ container?: string // Container
1067
+ icon?: string // Icon
1068
+ }
1069
+ ```
1070
+
1071
+ ### ChatMessageActionsUI
1072
+
1073
+ ```typescript
1074
+ interface ChatMessageActionsUI {
1075
+ container?: string // Container
1076
+ button?: string // Action button
1077
+ copyButton?: string // Copy button
1078
+ successState?: string // Success state
1079
+ }
1080
+ ```
1081
+
850
1082
  ## ๐Ÿ“ TypeScript Types
851
1083
 
852
1084
  All types are exported:
@@ -866,6 +1098,8 @@ import type {
866
1098
  ChatAttachment,
867
1099
  ChatRole,
868
1100
  SubmitPayload,
1101
+ Mention,
1102
+ ConversationHistoryItem,
869
1103
 
870
1104
  // Context
871
1105
  PageContext,
@@ -873,7 +1107,8 @@ import type {
873
1107
  // Providers
874
1108
  MentionProvider,
875
1109
  MentionItem,
876
- Mention,
1110
+ MentionContext,
1111
+ MentionParseResult,
877
1112
  SuggestionProvider,
878
1113
  AISuggestion,
879
1114
 
@@ -881,17 +1116,30 @@ import type {
881
1116
  HistoryLimitConfig,
882
1117
  LoadingTextConfig,
883
1118
 
1119
+ // Setup
1120
+ SetupStep,
1121
+ SetupState,
1122
+
1123
+ // Store
1124
+ AiStoreState,
1125
+
884
1126
  // UI Customization
885
1127
  AiChatDrawerUI,
886
1128
  ChatInputUI,
887
1129
  ChatMessageUI,
888
1130
  AiEmptyStateUI,
889
1131
  MentionListUI,
1132
+ AiAvatarUI,
1133
+ UserAvatarUI,
1134
+ ChatMessageActionsUI,
890
1135
 
891
1136
  // Text Customization
892
1137
  AiChatDrawerTexts,
893
1138
  ChatInputTexts,
894
1139
  ChatMessageTexts,
1140
+ AiEmptyStateTexts,
1141
+ MentionListTexts,
1142
+ ChatMessageActionsTexts,
895
1143
 
896
1144
  // Slot Props
897
1145
  HeaderSlotProps,
@@ -899,15 +1147,26 @@ import type {
899
1147
  InputSlotProps,
900
1148
  EmptyStateSlotProps,
901
1149
 
902
- // Hooks
1150
+ // API Hooks
1151
+ AiRequestPayload,
1152
+ AiStreamChunk,
903
1153
  BeforeSendHook,
904
1154
  AfterResponseHook,
905
1155
  OnStreamStartHook,
906
1156
  OnStreamEndHook,
907
1157
  OnStreamChunkHook,
908
1158
  StreamParserFunction,
1159
+ RequestInterceptor,
1160
+ ResponseInterceptor,
909
1161
  RetryConfig,
1162
+
1163
+ // Functions
1164
+ TranslateFunction,
1165
+ PermissionCheckFunction,
910
1166
  } from '@doderasoftware/restify-ai'
1167
+
1168
+ // Constants
1169
+ import { ChatRoles } from '@doderasoftware/restify-ai'
911
1170
  ```
912
1171
 
913
1172
  ## ๐Ÿ”Œ Backend Integration
@@ -924,25 +1183,101 @@ Route::post('/ask', [AiController::class, 'ask']);
924
1183
  **Request:**
925
1184
  ```json
926
1185
  {
927
- "question": "Who is available today?",
1186
+ "message": "Who is available today?",
928
1187
  "history": [
929
- { "role": "user", "message": "Hello" },
930
- { "role": "assistant", "message": "Hi! How can I help?" }
1188
+ { "role": "user", "content": "Hello" },
1189
+ { "role": "assistant", "content": "Hi! How can I help?" }
931
1190
  ],
932
1191
  "stream": true,
933
- "files": [{ "id": "file-123", "name": "report.pdf" }],
1192
+ "files": [{ "id": "file-123", "name": "report.pdf", "backendFileId": 456 }],
1193
+ "attachment_ids": [456],
934
1194
  "mentions": [{ "id": "emp-1", "type": "employee", "name": "John Doe" }],
935
- "contact_support": false
1195
+ "contact_support": false,
1196
+ "conversation_id": "conv-abc123"
936
1197
  }
937
1198
  ```
938
1199
 
1200
+ > **Note:** The `conversation_id` field is only sent when `useConversationId: true` is configured. The `attachment_ids` array contains backend file IDs returned from the upload endpoint.
1201
+
939
1202
  **Response (SSE):**
940
1203
  ```
1204
+ event: start
1205
+ data: {"conversation_id":"conv-abc123"}
1206
+
941
1207
  data: {"choices":[{"delta":{"content":"Based on"}}]}
942
1208
  data: {"choices":[{"delta":{"content":" the schedule..."}}]}
943
1209
  data: [DONE]
944
1210
  ```
945
1211
 
1212
+ ### Conversation ID Tracking
1213
+
1214
+ When `useConversationId: true` is enabled in the plugin configuration, the package will:
1215
+
1216
+ 1. **Receive** the conversation ID from the backend via the `start` SSE event
1217
+ 2. **Store** it in the Pinia store (`store.conversationId`)
1218
+ 3. **Send** it back with subsequent requests in the same conversation
1219
+ 4. **Clear** it when starting a new chat
1220
+
1221
+ This is useful for:
1222
+ - Tracking conversations across multiple requests
1223
+ - Maintaining context on the backend
1224
+ - Analytics and logging
1225
+ - Multi-turn conversation management
1226
+
1227
+ ### Conversation History
1228
+
1229
+ When `useConversationHistory: true` is enabled, users can access a sidebar showing their previous conversations:
1230
+
1231
+ **Features:**
1232
+ - ๐Ÿ“œ **View past conversations** - Browse through saved chats
1233
+ - โœ๏ธ **Rename conversations** - Give meaningful titles to chats
1234
+ - ๐Ÿ—‘๏ธ **Delete conversations** - Remove unwanted history
1235
+ - ๐Ÿ”„ **Switch conversations** - Seamlessly load previous chats
1236
+ - ๐Ÿ’พ **Automatic saving** - Conversations save automatically
1237
+
1238
+ **Configuration:**
1239
+ ```typescript
1240
+ app.use(RestifyAiPlugin, {
1241
+ useConversationId: true, // Required for history
1242
+ useConversationHistory: true, // Enable history sidebar
1243
+ maxConversationHistory: 10, // Max conversations to keep (default: 10)
1244
+ })
1245
+ ```
1246
+
1247
+ **How it works:**
1248
+ 1. When `useConversationHistory` is enabled, a history button appears in the drawer header
1249
+ 2. Clicking the button opens a sidebar showing past conversations
1250
+ 3. Conversations are automatically saved to `localStorage` when completed
1251
+ 4. Each conversation shows: title (from first message or backend), date, message count
1252
+ 5. Users can rename, delete, or switch between conversations
1253
+
1254
+ **Backend Integration:**
1255
+
1256
+ The backend can provide a conversation name via the `start` SSE event:
1257
+
1258
+ ```
1259
+ event: start
1260
+ data: {"conversation_id":"conv-abc123","conversation_name":"Budget Analysis Q1"}
1261
+ ```
1262
+
1263
+ If no name is provided, the title defaults to a truncated version of the first user message.
1264
+
1265
+ **Storage:**
1266
+ - Conversation list: `restify_ai_conversation_history`
1267
+ - Conversation messages: `restify_ai_conv_{conversationId}`
1268
+ - Current conversation ID: `restify_ai_current_conversation`
1269
+
1270
+ **ConversationHistoryItem Interface:**
1271
+ ```typescript
1272
+ interface ConversationHistoryItem {
1273
+ id: string // Conversation ID from backend
1274
+ title: string // Display title
1275
+ createdAt: number // Timestamp when created
1276
+ updatedAt: number // Timestamp of last update
1277
+ messageCount: number // Number of messages
1278
+ }
1279
+ ```
1280
+
946
1281
  ### Quota Endpoint
947
1282
 
948
1283
  ```php
@@ -961,6 +1296,27 @@ Route::get('/ai/quota', [AiController::class, 'quota']);
961
1296
  }
962
1297
  ```
963
1298
 
1299
+ ### Rate Limiting via Headers
1300
+
1301
+ As an alternative to the quota endpoint, you can enable headers-based rate limiting. When `useHeadersRateLimiter` is enabled, the package will extract rate limit information directly from response headers instead of making separate quota endpoint calls.
1302
+
1303
+ **Configuration:**
1304
+ ```typescript
1305
+ app.use(RestifyAi, {
1306
+ useQuota: true,
1307
+ useHeadersRateLimiter: true, // Enable headers-based rate limiting
1308
+ })
1309
+ ```
1310
+
1311
+ **Required Response Headers:**
1312
+
1313
+ Your chat endpoint should return these headers with each response:
1314
+
1315
+ ```
1316
+ x-ratelimit-limit: 100 // Total allowed requests
1317
+ x-ratelimit-remaining: 75 // Remaining requests
1318
+ ```
1319
+
964
1320
  ### Upload Endpoint
965
1321
 
966
1322
  ```php
@@ -972,15 +1328,41 @@ Route::post('/ai/upload', [AiController::class, 'upload']);
972
1328
  ```json
973
1329
  {
974
1330
  "data": {
975
- "id": "file-123",
1331
+ "id": 456,
976
1332
  "name": "document.pdf",
977
1333
  "url": "/storage/uploads/document.pdf",
978
1334
  "type": "application/pdf",
979
- "size": 102400
1335
+ "size": 102400,
1336
+ "extracted_text": "Optional extracted text content..."
980
1337
  }
981
1338
  }
982
1339
  ```
983
1340
 
1341
+ ### Backend File ID Support
1342
+
1343
+ When files are uploaded, the backend can return an ID that will be automatically tracked and sent with subsequent requests. This enables the backend to reference pre-processed files.
1344
+
1345
+ **Supported ID field names in upload response:**
1346
+ - `id` (recommended)
1347
+ - `file_id`
1348
+ - `attachment_id`
1349
+ - `openai_file_id`
1350
+
1351
+ The package automatically:
1352
+ 1. **Stores** the backend file ID when received from upload response
1353
+ 2. **Includes** all backend file IDs in the `attachment_ids` array in ask requests
1354
+ 3. **Preserves** the ID through the entire conversation
1355
+
1356
+ **Example flow:**
1357
+ ```
1358
+ 1. User uploads file.pdf
1359
+ 2. Backend returns: { "id": 456, "name": "file.pdf", ... }
1360
+ 3. Package stores backendFileId: 456
1361
+ 4. User sends message with attachment
1362
+ 5. Request includes: { "attachment_ids": [456], "files": [...] }
1363
+ 6. Backend can use attachment_ids to reference stored/processed files
1364
+ ```
1365
+
984
1366
  ## โŒจ๏ธ Keyboard Shortcuts
985
1367
 
986
1368
  | Shortcut | Action |
@@ -1002,7 +1384,17 @@ Chat history persists in `sessionStorage` by default:
1002
1384
 
1003
1385
  ```typescript
1004
1386
  // Components
1005
- export { AiChatDrawer } from './components'
1387
+ export {
1388
+ AiChatDrawer,
1389
+ AiEmptyState,
1390
+ ChatInput,
1391
+ ChatMessage,
1392
+ ChatMessageActions,
1393
+ MentionList,
1394
+ AiAvatar,
1395
+ UserAvatar,
1396
+ ErrorBoundary,
1397
+ } from './components'
1006
1398
 
1007
1399
  // Store
1008
1400
  export { useRestifyAiStore } from './store'
@@ -1010,20 +1402,42 @@ export { useRestifyAiStore } from './store'
1010
1402
  // Composables
1011
1403
  export {
1012
1404
  useAiDrawerShortcut,
1405
+ useKeyboardShortcut,
1013
1406
  usePageAiContext,
1014
1407
  useAiContext,
1015
- useAiSuggestions
1408
+ useAiSuggestions,
1409
+ useMentionParsing,
1410
+ useChatMarkdown,
1411
+ useChatScroll,
1412
+ useChatErrorHandling,
1413
+ useLoadingText,
1414
+ useHistoryLimit,
1415
+ useSuggestionFilter,
1416
+ useAutoScroll,
1417
+ formatMentionsForApi,
1418
+ groupMentionsByType,
1016
1419
  } from './composables'
1017
1420
 
1018
1421
  // Config
1019
1422
  export {
1020
- initRestifyAi,
1021
- getConfig,
1022
- getLabels,
1023
- getUI,
1024
- RestifyAiPlugin
1423
+ RestifyAiPlugin,
1424
+ getRestifyAiConfig,
1425
+ setRestifyAiConfig,
1426
+ getLabel,
1427
+ getConfigValue,
1428
+ isConfigured,
1429
+ defaultLabels,
1025
1430
  } from './config'
1026
1431
 
1432
+ // Suggestions
1433
+ export {
1434
+ registerSuggestionProvider,
1435
+ getSuggestionsForPath,
1436
+ } from './suggestions'
1437
+
1438
+ // Utilities
1439
+ export { isImageFile, formatFileSize } from './utils'
1440
+
1027
1441
  // Types
1028
1442
  export * from './types'
1029
1443
  ```
@@ -1039,7 +1453,7 @@ export * from './types'
1039
1453
  - [๐Ÿ“– Laravel Restify Documentation](https://laravel-restify.com)
1040
1454
  - [๐Ÿ“ฆ npm Package](https://www.npmjs.com/package/@doderasoftware/restify-ai)
1041
1455
  - [๐Ÿข BinarCode](https://binarcode.com)
1042
- - [๐Ÿ’ป GitHub](https://github.com/BinarCode/laravel-restify)
1456
+ - [๐Ÿ’ป GitHub](https://github.com/BinarCode/restify-chatbot)
1043
1457
 
1044
1458
  ## ๐Ÿ“„ License
1045
1459
 
@@ -1047,4 +1461,4 @@ MIT ยฉ [BinarCode](https://binarcode.com)
1047
1461
 
1048
1462
  ---
1049
1463
 
1050
- Built with โค๏ธ by the [BinarCode](https://binarcode.com) team ยท Published by [Dodera Software](https://doderasoft.com)
1464
+ Built with โค๏ธ by the [BinarCode](https://binarcode.com) team.