@retrivora-ai/rag-engine 1.2.1 → 1.2.2

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 (43) hide show
  1. package/dist/DocumentChunker-BXOUMKoP.d.ts +93 -0
  2. package/dist/DocumentChunker-D1dg5iCi.d.mts +93 -0
  3. package/dist/handlers/index.d.mts +2 -2
  4. package/dist/handlers/index.d.ts +2 -2
  5. package/dist/{index-DbtE8wLM.d.ts → index-B67KQ9NN.d.ts} +1 -1
  6. package/dist/{RagConfig-BOLOz0_O.d.mts → index-Cti1u0y1.d.mts} +86 -94
  7. package/dist/{RagConfig-BOLOz0_O.d.ts → index-Cti1u0y1.d.ts} +86 -94
  8. package/dist/{index-64BDupW3.d.mts → index-kUXnRvuI.d.mts} +1 -1
  9. package/dist/index.d.mts +52 -78
  10. package/dist/index.d.ts +52 -78
  11. package/dist/index.js +93 -27
  12. package/dist/index.mjs +97 -27
  13. package/dist/server.d.mts +5 -4
  14. package/dist/server.d.ts +5 -4
  15. package/package.json +1 -1
  16. package/src/components/ChatWidget.tsx +1 -8
  17. package/src/components/ChatWindow.tsx +119 -29
  18. package/src/components/ConfigProvider.tsx +7 -33
  19. package/src/components/DocumentUpload.tsx +1 -8
  20. package/src/components/MessageBubble.tsx +1 -12
  21. package/src/components/ProductCard.tsx +1 -7
  22. package/src/components/ProductCarousel.tsx +1 -7
  23. package/src/components/SourceCard.tsx +1 -6
  24. package/src/config/RagConfig.ts +2 -0
  25. package/src/config/uiConstants.ts +23 -0
  26. package/src/core/Pipeline.ts +2 -1
  27. package/src/core/VectorPlugin.ts +1 -1
  28. package/src/handlers/index.ts +1 -1
  29. package/src/hooks/useRagChat.ts +1 -45
  30. package/src/hooks/useStoredMessages.ts +1 -1
  31. package/src/index.ts +20 -5
  32. package/src/llm/ILLMProvider.ts +1 -13
  33. package/src/llm/providers/AnthropicProvider.ts +2 -1
  34. package/src/llm/providers/GeminiProvider.ts +2 -1
  35. package/src/llm/providers/OllamaProvider.ts +2 -1
  36. package/src/llm/providers/OpenAIProvider.ts +2 -1
  37. package/src/llm/providers/UniversalLLMAdapter.ts +2 -1
  38. package/src/server.ts +2 -2
  39. package/src/types/chat.ts +53 -0
  40. package/src/types/index.ts +3 -0
  41. package/src/types/props.ts +79 -0
  42. package/dist/DocumentChunker-Dh9TvmGG.d.mts +0 -45
  43. package/dist/DocumentChunker-Dh9TvmGG.d.ts +0 -45
package/dist/index.d.mts CHANGED
@@ -1,27 +1,19 @@
1
- import React$1, { ReactNode } from 'react';
2
- import { P as Product, C as ChatMessage, V as VectorMatch, U as UIConfig } from './RagConfig-BOLOz0_O.mjs';
3
- export { a as ChatOptions, b as ChatResponse, E as EmbedOptions, c as EmbeddingConfig, d as EmbeddingProvider, I as ILLMProvider, e as IngestDocument, L as LLMConfig, f as LLMProvider, R as RAGConfig, g as RagConfig, h as UpsertDocument, i as VectorDBConfig, j as VectorDBProvider } from './RagConfig-BOLOz0_O.mjs';
4
- export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.mjs';
5
-
6
- interface ChatWidgetProps {
7
- /** Position of the floating button. Defaults to bottom-right. */
8
- position?: 'bottom-right' | 'bottom-left';
9
- /** Called when the user clicks 'Add to Cart' on a product */
10
- onAddToCart?: (product: Product) => void;
11
- }
12
- declare function ChatWidget({ position, onAddToCart }: ChatWidgetProps): React$1.JSX.Element | null;
1
+ import React, { CSSProperties, MouseEvent, ReactNode } from 'react';
2
+ import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, a as UseRagChatOptions, b as UseRagChatReturn } from './index-Cti1u0y1.mjs';
3
+ export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbeddingConfig, e as EmbeddingProvider, I as IngestDocument, L as LLMConfig, f as LLMProvider, g as RAGConfig, h as RagConfig, i as UpsertDocument, j as VectorDBConfig, k as VectorDBProvider } from './index-Cti1u0y1.mjs';
4
+ export { C as Chunk, a as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-D1dg5iCi.mjs';
13
5
 
14
6
  interface ChatWindowProps {
15
7
  /** Additional className for the wrapper div */
16
8
  className?: string;
17
9
  /** Inline styles for the wrapper div */
18
- style?: React$1.CSSProperties;
10
+ style?: CSSProperties;
19
11
  /** Called when the close button is clicked (for widget mode) */
20
12
  onClose?: () => void;
21
13
  /** Whether to show a close (X) button in the header */
22
14
  showClose?: boolean;
23
15
  /** Called when the user starts dragging the resize handle */
24
- onResizeStart?: (e: React$1.MouseEvent) => void;
16
+ onResizeStart?: (e: MouseEvent) => void;
25
17
  /** Called when the user clicks the reset size button */
26
18
  onResetResize?: () => void;
27
19
  /** Whether the window has been resized from its default */
@@ -33,8 +25,30 @@ interface ChatWindowProps {
33
25
  /** Called when the user clicks 'Add to Cart' on a product */
34
26
  onAddToCart?: (product: Product) => void;
35
27
  }
36
- declare function ChatWindow({ className, style, onClose, showClose, onResizeStart, onResetResize, isResized, onMaximize, isMaximized, onAddToCart }: ChatWindowProps): React$1.JSX.Element;
37
-
28
+ interface ChatWidgetProps {
29
+ /** Position of the floating button. Defaults to bottom-right. */
30
+ position?: 'bottom-right' | 'bottom-left';
31
+ /** Called when the user clicks 'Add to Cart' on a product */
32
+ onAddToCart?: (product: Product) => void;
33
+ }
34
+ interface MessageBubbleProps {
35
+ message: RagMessage;
36
+ sources?: VectorMatch[];
37
+ isStreaming?: boolean;
38
+ primaryColor: string;
39
+ accentColor: string;
40
+ onAddToCart?: (product: Product) => void;
41
+ }
42
+ interface ProductCardProps {
43
+ product: Product;
44
+ primaryColor?: string;
45
+ onAddToCart?: (product: Product) => void;
46
+ }
47
+ interface ProductCarouselProps {
48
+ products: Product[];
49
+ primaryColor?: string;
50
+ onAddToCart?: (product: Product) => void;
51
+ }
38
52
  interface DocumentUploadProps {
39
53
  /** Optional namespace for the upload */
40
54
  namespace?: string;
@@ -43,82 +57,42 @@ interface DocumentUploadProps {
43
57
  /** Additional className */
44
58
  className?: string;
45
59
  }
46
- declare function DocumentUpload({ namespace, onUploadComplete, className }: DocumentUploadProps): React$1.JSX.Element;
47
-
48
- interface MessageBubbleProps {
49
- message: ChatMessage;
50
- sources?: VectorMatch[];
51
- isStreaming?: boolean;
52
- primaryColor?: string;
53
- accentColor?: string;
54
- onAddToCart?: (product: Product) => void;
55
- }
56
- declare function MessageBubble({ message, sources, isStreaming, primaryColor, accentColor, onAddToCart, }: MessageBubbleProps): React$1.JSX.Element;
57
-
58
60
  interface SourceCardProps {
59
61
  source: VectorMatch;
60
62
  index: number;
61
63
  }
62
- declare function SourceCard({ source, index }: SourceCardProps): React$1.JSX.Element;
63
-
64
- /**
65
- * ConfigProvider — React Context that makes RagConfig (UI subset) available
66
- * to all child components without prop drilling.
67
- *
68
- * Only the UI-safe portions of RagConfig are exposed to the client.
69
- */
70
-
71
64
  interface ClientConfig {
72
65
  projectId: string;
73
66
  ui: Required<UIConfig>;
74
67
  }
75
- declare function ConfigProvider({ config, children, }: {
68
+ interface ConfigProviderProps {
76
69
  config?: {
77
70
  projectId?: string;
78
71
  ui?: Partial<UIConfig>;
79
72
  };
80
73
  children: ReactNode;
81
- }): React$1.JSX.Element;
74
+ }
75
+
76
+ declare function ChatWidget({ position, onAddToCart }: ChatWidgetProps): React.JSX.Element | null;
77
+
78
+ declare function ChatWindow({ className, style, onClose, showClose, onResizeStart, onResetResize, isResized, onMaximize, isMaximized, onAddToCart }: ChatWindowProps): React.JSX.Element;
79
+
80
+ declare function DocumentUpload({ namespace, onUploadComplete, className }: DocumentUploadProps): React.JSX.Element;
81
+
82
+ declare function MessageBubble({ message, sources, isStreaming, primaryColor, accentColor, onAddToCart, }: MessageBubbleProps): React.JSX.Element;
83
+
84
+ declare function SourceCard({ source, index }: SourceCardProps): React.JSX.Element;
85
+
86
+ /**
87
+ * ConfigProvider — React Context that makes RagConfig (UI subset) available
88
+ * to all child components without prop drilling.
89
+ *
90
+ * Only the UI-safe portions of RagConfig are exposed to the client.
91
+ */
92
+
93
+ declare function ConfigProvider({ config, children, }: ConfigProviderProps): React.JSX.Element;
82
94
  declare function useConfig(): ClientConfig;
83
95
 
84
- type MessageRole = 'user' | 'assistant';
85
- interface RagMessage {
86
- id: string;
87
- role: MessageRole;
88
- content: string;
89
- /** Retrieved source chunks (assistant messages only) */
90
- sources?: VectorMatch[];
91
- /** ISO timestamp */
92
- createdAt: string;
93
- }
94
- interface UseRagChatOptions {
95
- /** Override the chat API endpoint (default: /api/chat) */
96
- apiUrl?: string;
97
- /** Override project namespace */
98
- namespace?: string;
99
- /** Persist chat history to localStorage (default: true) */
100
- persist?: boolean;
101
- /** Called after each successful assistant reply */
102
- onReply?: (message: RagMessage) => void;
103
- /** Called on error */
104
- onError?: (error: string) => void;
105
- }
106
- interface UseRagChatReturn {
107
- /** All messages in the current conversation */
108
- messages: RagMessage[];
109
- /** Whether a response is in flight */
110
- isLoading: boolean;
111
- /** Current error message, or null */
112
- error: string | null;
113
- /** Send a user message */
114
- send: (text: string) => Promise<void>;
115
- /** Clear the conversation (and localStorage if persist=true) */
116
- clear: () => void;
117
- /** Retry the last failed send */
118
- retry: () => Promise<void>;
119
- /** Programmatically set the conversation (e.g. to restore from a DB) */
120
- setMessages: React.Dispatch<React.SetStateAction<RagMessage[]>>;
121
- }
122
96
  declare function useRagChat(projectId: string, options?: UseRagChatOptions): UseRagChatReturn;
123
97
 
124
- export { ChatMessage, ChatWidget, ChatWindow, type ClientConfig, ConfigProvider, DocumentUpload, MessageBubble, type RagMessage, SourceCard, UIConfig, type UseRagChatOptions, type UseRagChatReturn, VectorMatch, useConfig, useRagChat };
98
+ export { ChatWidget, type ChatWidgetProps, ChatWindow, type ChatWindowProps, type ClientConfig, ConfigProvider, DocumentUpload, type DocumentUploadProps, MessageBubble, type MessageBubbleProps, type ProductCardProps, type ProductCarouselProps, RagMessage, SourceCard, type SourceCardProps, UIConfig, UseRagChatOptions, UseRagChatReturn, VectorMatch, useConfig, useRagChat };
package/dist/index.d.ts CHANGED
@@ -1,27 +1,19 @@
1
- import React$1, { ReactNode } from 'react';
2
- import { P as Product, C as ChatMessage, V as VectorMatch, U as UIConfig } from './RagConfig-BOLOz0_O.js';
3
- export { a as ChatOptions, b as ChatResponse, E as EmbedOptions, c as EmbeddingConfig, d as EmbeddingProvider, I as ILLMProvider, e as IngestDocument, L as LLMConfig, f as LLMProvider, R as RAGConfig, g as RagConfig, h as UpsertDocument, i as VectorDBConfig, j as VectorDBProvider } from './RagConfig-BOLOz0_O.js';
4
- export { C as Chunk, a as ChunkOptions } from './DocumentChunker-Dh9TvmGG.js';
5
-
6
- interface ChatWidgetProps {
7
- /** Position of the floating button. Defaults to bottom-right. */
8
- position?: 'bottom-right' | 'bottom-left';
9
- /** Called when the user clicks 'Add to Cart' on a product */
10
- onAddToCart?: (product: Product) => void;
11
- }
12
- declare function ChatWidget({ position, onAddToCart }: ChatWidgetProps): React$1.JSX.Element | null;
1
+ import React, { CSSProperties, MouseEvent, ReactNode } from 'react';
2
+ import { P as Product, U as UIConfig, R as RagMessage, V as VectorMatch, a as UseRagChatOptions, b as UseRagChatReturn } from './index-Cti1u0y1.js';
3
+ export { C as ChatMessage, c as ChatOptions, d as ChatResponse, E as EmbeddingConfig, e as EmbeddingProvider, I as IngestDocument, L as LLMConfig, f as LLMProvider, g as RAGConfig, h as RagConfig, i as UpsertDocument, j as VectorDBConfig, k as VectorDBProvider } from './index-Cti1u0y1.js';
4
+ export { C as Chunk, a as ChunkOptions, E as EmbedOptions, I as ILLMProvider } from './DocumentChunker-BXOUMKoP.js';
13
5
 
14
6
  interface ChatWindowProps {
15
7
  /** Additional className for the wrapper div */
16
8
  className?: string;
17
9
  /** Inline styles for the wrapper div */
18
- style?: React$1.CSSProperties;
10
+ style?: CSSProperties;
19
11
  /** Called when the close button is clicked (for widget mode) */
20
12
  onClose?: () => void;
21
13
  /** Whether to show a close (X) button in the header */
22
14
  showClose?: boolean;
23
15
  /** Called when the user starts dragging the resize handle */
24
- onResizeStart?: (e: React$1.MouseEvent) => void;
16
+ onResizeStart?: (e: MouseEvent) => void;
25
17
  /** Called when the user clicks the reset size button */
26
18
  onResetResize?: () => void;
27
19
  /** Whether the window has been resized from its default */
@@ -33,8 +25,30 @@ interface ChatWindowProps {
33
25
  /** Called when the user clicks 'Add to Cart' on a product */
34
26
  onAddToCart?: (product: Product) => void;
35
27
  }
36
- declare function ChatWindow({ className, style, onClose, showClose, onResizeStart, onResetResize, isResized, onMaximize, isMaximized, onAddToCart }: ChatWindowProps): React$1.JSX.Element;
37
-
28
+ interface ChatWidgetProps {
29
+ /** Position of the floating button. Defaults to bottom-right. */
30
+ position?: 'bottom-right' | 'bottom-left';
31
+ /** Called when the user clicks 'Add to Cart' on a product */
32
+ onAddToCart?: (product: Product) => void;
33
+ }
34
+ interface MessageBubbleProps {
35
+ message: RagMessage;
36
+ sources?: VectorMatch[];
37
+ isStreaming?: boolean;
38
+ primaryColor: string;
39
+ accentColor: string;
40
+ onAddToCart?: (product: Product) => void;
41
+ }
42
+ interface ProductCardProps {
43
+ product: Product;
44
+ primaryColor?: string;
45
+ onAddToCart?: (product: Product) => void;
46
+ }
47
+ interface ProductCarouselProps {
48
+ products: Product[];
49
+ primaryColor?: string;
50
+ onAddToCart?: (product: Product) => void;
51
+ }
38
52
  interface DocumentUploadProps {
39
53
  /** Optional namespace for the upload */
40
54
  namespace?: string;
@@ -43,82 +57,42 @@ interface DocumentUploadProps {
43
57
  /** Additional className */
44
58
  className?: string;
45
59
  }
46
- declare function DocumentUpload({ namespace, onUploadComplete, className }: DocumentUploadProps): React$1.JSX.Element;
47
-
48
- interface MessageBubbleProps {
49
- message: ChatMessage;
50
- sources?: VectorMatch[];
51
- isStreaming?: boolean;
52
- primaryColor?: string;
53
- accentColor?: string;
54
- onAddToCart?: (product: Product) => void;
55
- }
56
- declare function MessageBubble({ message, sources, isStreaming, primaryColor, accentColor, onAddToCart, }: MessageBubbleProps): React$1.JSX.Element;
57
-
58
60
  interface SourceCardProps {
59
61
  source: VectorMatch;
60
62
  index: number;
61
63
  }
62
- declare function SourceCard({ source, index }: SourceCardProps): React$1.JSX.Element;
63
-
64
- /**
65
- * ConfigProvider — React Context that makes RagConfig (UI subset) available
66
- * to all child components without prop drilling.
67
- *
68
- * Only the UI-safe portions of RagConfig are exposed to the client.
69
- */
70
-
71
64
  interface ClientConfig {
72
65
  projectId: string;
73
66
  ui: Required<UIConfig>;
74
67
  }
75
- declare function ConfigProvider({ config, children, }: {
68
+ interface ConfigProviderProps {
76
69
  config?: {
77
70
  projectId?: string;
78
71
  ui?: Partial<UIConfig>;
79
72
  };
80
73
  children: ReactNode;
81
- }): React$1.JSX.Element;
74
+ }
75
+
76
+ declare function ChatWidget({ position, onAddToCart }: ChatWidgetProps): React.JSX.Element | null;
77
+
78
+ declare function ChatWindow({ className, style, onClose, showClose, onResizeStart, onResetResize, isResized, onMaximize, isMaximized, onAddToCart }: ChatWindowProps): React.JSX.Element;
79
+
80
+ declare function DocumentUpload({ namespace, onUploadComplete, className }: DocumentUploadProps): React.JSX.Element;
81
+
82
+ declare function MessageBubble({ message, sources, isStreaming, primaryColor, accentColor, onAddToCart, }: MessageBubbleProps): React.JSX.Element;
83
+
84
+ declare function SourceCard({ source, index }: SourceCardProps): React.JSX.Element;
85
+
86
+ /**
87
+ * ConfigProvider — React Context that makes RagConfig (UI subset) available
88
+ * to all child components without prop drilling.
89
+ *
90
+ * Only the UI-safe portions of RagConfig are exposed to the client.
91
+ */
92
+
93
+ declare function ConfigProvider({ config, children, }: ConfigProviderProps): React.JSX.Element;
82
94
  declare function useConfig(): ClientConfig;
83
95
 
84
- type MessageRole = 'user' | 'assistant';
85
- interface RagMessage {
86
- id: string;
87
- role: MessageRole;
88
- content: string;
89
- /** Retrieved source chunks (assistant messages only) */
90
- sources?: VectorMatch[];
91
- /** ISO timestamp */
92
- createdAt: string;
93
- }
94
- interface UseRagChatOptions {
95
- /** Override the chat API endpoint (default: /api/chat) */
96
- apiUrl?: string;
97
- /** Override project namespace */
98
- namespace?: string;
99
- /** Persist chat history to localStorage (default: true) */
100
- persist?: boolean;
101
- /** Called after each successful assistant reply */
102
- onReply?: (message: RagMessage) => void;
103
- /** Called on error */
104
- onError?: (error: string) => void;
105
- }
106
- interface UseRagChatReturn {
107
- /** All messages in the current conversation */
108
- messages: RagMessage[];
109
- /** Whether a response is in flight */
110
- isLoading: boolean;
111
- /** Current error message, or null */
112
- error: string | null;
113
- /** Send a user message */
114
- send: (text: string) => Promise<void>;
115
- /** Clear the conversation (and localStorage if persist=true) */
116
- clear: () => void;
117
- /** Retry the last failed send */
118
- retry: () => Promise<void>;
119
- /** Programmatically set the conversation (e.g. to restore from a DB) */
120
- setMessages: React.Dispatch<React.SetStateAction<RagMessage[]>>;
121
- }
122
96
  declare function useRagChat(projectId: string, options?: UseRagChatOptions): UseRagChatReturn;
123
97
 
124
- export { ChatMessage, ChatWidget, ChatWindow, type ClientConfig, ConfigProvider, DocumentUpload, MessageBubble, type RagMessage, SourceCard, UIConfig, type UseRagChatOptions, type UseRagChatReturn, VectorMatch, useConfig, useRagChat };
98
+ export { ChatWidget, type ChatWidgetProps, ChatWindow, type ChatWindowProps, type ClientConfig, ConfigProvider, DocumentUpload, type DocumentUploadProps, MessageBubble, type MessageBubbleProps, type ProductCardProps, type ProductCarouselProps, RagMessage, SourceCard, type SourceCardProps, UIConfig, UseRagChatOptions, UseRagChatReturn, VectorMatch, useConfig, useRagChat };
package/dist/index.js CHANGED
@@ -338,8 +338,8 @@ function mergeDefined(base, override) {
338
338
  return merged;
339
339
  }
340
340
 
341
- // src/components/ConfigProvider.tsx
342
- var defaultConfig = {
341
+ // src/config/uiConstants.ts
342
+ var DEFAULT_CONFIG = {
343
343
  projectId: "default",
344
344
  ui: {
345
345
  title: "AI Assistant",
@@ -355,17 +355,33 @@ var defaultConfig = {
355
355
  visualStyle: "glass",
356
356
  borderRadius: "xl",
357
357
  allowUpload: true,
358
- allowResize: true
358
+ allowResize: true,
359
+ enableVoiceInput: true
359
360
  }
360
361
  };
361
- var ConfigContext = (0, import_react5.createContext)(defaultConfig);
362
+ var BORDER_RADIUS_MAP = {
363
+ none: "rounded-none",
364
+ sm: "rounded-sm",
365
+ md: "rounded-md",
366
+ lg: "rounded-lg",
367
+ xl: "rounded-xl",
368
+ full: "rounded-3xl"
369
+ };
370
+ var CHAT_SUGGESTIONS = [
371
+ "What can you help me with?",
372
+ "Summarise the key topics",
373
+ "Show me an example"
374
+ ];
375
+
376
+ // src/components/ConfigProvider.tsx
377
+ var ConfigContext = (0, import_react5.createContext)(DEFAULT_CONFIG);
362
378
  function ConfigProvider({
363
379
  config,
364
380
  children
365
381
  }) {
366
382
  const merged = {
367
- projectId: (config == null ? void 0 : config.projectId) || defaultConfig.projectId,
368
- ui: mergeDefined(defaultConfig.ui, config == null ? void 0 : config.ui)
383
+ projectId: (config == null ? void 0 : config.projectId) || DEFAULT_CONFIG.projectId,
384
+ ui: mergeDefined(DEFAULT_CONFIG.ui, config == null ? void 0 : config.ui)
369
385
  };
370
386
  return /* @__PURE__ */ import_react5.default.createElement(ConfigContext.Provider, { value: merged }, children);
371
387
  }
@@ -563,21 +579,6 @@ function useRagChat(projectId, options = {}) {
563
579
  };
564
580
  }
565
581
 
566
- // src/config/uiConstants.ts
567
- var BORDER_RADIUS_MAP = {
568
- none: "rounded-none",
569
- sm: "rounded-sm",
570
- md: "rounded-md",
571
- lg: "rounded-lg",
572
- xl: "rounded-xl",
573
- full: "rounded-3xl"
574
- };
575
- var CHAT_SUGGESTIONS = [
576
- "What can you help me with?",
577
- "Summarise the key topics",
578
- "Show me an example"
579
- ];
580
-
581
582
  // src/components/ChatWindow.tsx
582
583
  function ChatWindow({
583
584
  className = "",
@@ -600,6 +601,56 @@ function ChatWindow({
600
601
  const { messages, send, clear, isLoading, error } = useRagChat(projectId, {
601
602
  namespace: projectId
602
603
  });
604
+ const [suggestions, setSuggestions] = (0, import_react7.useState)([]);
605
+ const [isSuggesting, setIsSuggesting] = (0, import_react7.useState)(false);
606
+ const [isListening, setIsListening] = (0, import_react7.useState)(false);
607
+ const recognitionRef = (0, import_react7.useRef)(null);
608
+ (0, import_react7.useEffect)(() => {
609
+ if (typeof window !== "undefined") {
610
+ const win = window;
611
+ const SpeechRecognition = win.SpeechRecognition || win.webkitSpeechRecognition;
612
+ if (SpeechRecognition) {
613
+ const recognition = new SpeechRecognition();
614
+ recognition.continuous = true;
615
+ recognition.interimResults = true;
616
+ recognition.onresult = (event) => {
617
+ let finalTranscript = "";
618
+ for (let i = event.resultIndex; i < event.results.length; ++i) {
619
+ if (event.results[i].isFinal) {
620
+ finalTranscript += event.results[i][0].transcript;
621
+ }
622
+ }
623
+ if (finalTranscript) {
624
+ setInput((prev) => (prev ? prev + " " : "") + finalTranscript.trim());
625
+ }
626
+ };
627
+ recognition.onerror = (event) => {
628
+ console.error("Speech recognition error:", event.error);
629
+ setIsListening(false);
630
+ };
631
+ recognition.onend = () => {
632
+ setIsListening(false);
633
+ };
634
+ recognitionRef.current = recognition;
635
+ }
636
+ }
637
+ }, []);
638
+ const toggleListening = () => {
639
+ if (!recognitionRef.current) {
640
+ alert("Speech recognition is not supported in your browser.");
641
+ return;
642
+ }
643
+ if (isListening) {
644
+ recognitionRef.current.stop();
645
+ } else {
646
+ try {
647
+ recognitionRef.current.start();
648
+ setIsListening(true);
649
+ } catch (err) {
650
+ console.error("Failed to start recognition:", err);
651
+ }
652
+ }
653
+ };
603
654
  (0, import_react7.useEffect)(() => {
604
655
  setMounted(true);
605
656
  }, []);
@@ -610,15 +661,21 @@ function ChatWindow({
610
661
  }
611
662
  }, [messages, isLoading]);
612
663
  const sendMessage = (0, import_react7.useCallback)(async () => {
664
+ var _a2;
613
665
  const text = input.trim();
614
666
  if (!text || isLoading) return;
667
+ if (isListening) {
668
+ (_a2 = recognitionRef.current) == null ? void 0 : _a2.stop();
669
+ }
615
670
  setInput("");
671
+ setSuggestions([]);
672
+ setIsSuggesting(false);
616
673
  await send(text);
617
674
  window.setTimeout(() => {
618
- var _a2;
619
- return (_a2 = inputRef.current) == null ? void 0 : _a2.focus();
675
+ var _a3;
676
+ return (_a3 = inputRef.current) == null ? void 0 : _a3.focus();
620
677
  }, 50);
621
- }, [input, isLoading, send]);
678
+ }, [input, isLoading, send, isListening]);
622
679
  const handleKeyDown = (e) => {
623
680
  if (e.key === "Enter" && !e.shiftKey) {
624
681
  e.preventDefault();
@@ -627,12 +684,12 @@ function ChatWindow({
627
684
  };
628
685
  const clearHistory = () => {
629
686
  clear();
687
+ setSuggestions([]);
688
+ setIsSuggesting(false);
630
689
  };
631
690
  const isEmpty = messages.length === 0;
632
691
  const currentRadius = BORDER_RADIUS_MAP[ui.borderRadius || "xl"];
633
692
  const isGlass = ui.visualStyle !== "solid";
634
- const [suggestions, setSuggestions] = (0, import_react7.useState)([]);
635
- const [isSuggesting, setIsSuggesting] = (0, import_react7.useState)(false);
636
693
  (0, import_react7.useEffect)(() => {
637
694
  if (input.trim().length < 3) {
638
695
  return;
@@ -761,7 +818,7 @@ function ChatWindow({
761
818
  )), isLoading && ((_a = messages[messages.length - 1]) == null ? void 0 : _a.role) !== "assistant" && /* @__PURE__ */ import_react7.default.createElement(
762
819
  MessageBubble,
763
820
  {
764
- message: { role: "assistant", content: "" },
821
+ message: { id: "loading", role: "assistant", content: "", createdAt: (/* @__PURE__ */ new Date()).toISOString() },
765
822
  isStreaming: true,
766
823
  primaryColor: ui.primaryColor,
767
824
  accentColor: ui.accentColor,
@@ -801,6 +858,15 @@ function ChatWindow({
801
858
  className: "flex-1 bg-transparent text-slate-900 dark:text-white/90 placeholder-slate-400 dark:placeholder-white/30 text-sm resize-none outline-none py-1.5 px-2 max-h-32 leading-relaxed disabled:opacity-50",
802
859
  style: { scrollbarWidth: "none" }
803
860
  }
861
+ ), ui.enableVoiceInput !== false && /* @__PURE__ */ import_react7.default.createElement(
862
+ "button",
863
+ {
864
+ type: "button",
865
+ onClick: toggleListening,
866
+ className: `flex-shrink-0 w-9 h-9 rounded-xl flex items-center justify-center transition-all hover:scale-105 active:scale-95 ${isListening ? "bg-rose-500 text-white animate-pulse shadow-md shadow-rose-500/20" : "text-slate-400 dark:text-white/40 hover:bg-slate-200 dark:hover:bg-white/10"}`,
867
+ title: isListening ? "Stop listening" : "Start voice input"
868
+ },
869
+ isListening ? /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.MicOff, { className: "w-4 h-4" }) : /* @__PURE__ */ import_react7.default.createElement(import_lucide_react5.Mic, { className: "w-4 h-4" })
804
870
  ), /* @__PURE__ */ import_react7.default.createElement(
805
871
  "button",
806
872
  {