@chatwidgetai/chat-widget 0.1.7 → 0.1.9

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/index.js CHANGED
@@ -195,6 +195,124 @@ class WidgetApiClient {
195
195
  throw error;
196
196
  }
197
197
  }
198
+ /**
199
+ * Stream chat message responses
200
+ */
201
+ async *sendMessageStream(conversationId, message, fileIds) {
202
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/chat`, {
203
+ method: 'POST',
204
+ headers: {
205
+ 'Content-Type': 'application/json',
206
+ },
207
+ body: JSON.stringify({
208
+ conversationId: conversationId,
209
+ message,
210
+ fileIds,
211
+ timeZone: this.getTimeZone(),
212
+ }),
213
+ });
214
+ if (!response.ok) {
215
+ throw await buildApiError(response, 'Failed to send message');
216
+ }
217
+ if (!response.body) {
218
+ throw new Error('Response body is null');
219
+ }
220
+ const reader = response.body.getReader();
221
+ const decoder = new TextDecoder();
222
+ let buffer = '';
223
+ try {
224
+ while (true) {
225
+ const { done, value } = await reader.read();
226
+ if (done)
227
+ break;
228
+ buffer += decoder.decode(value, { stream: true });
229
+ const lines = buffer.split('\n');
230
+ buffer = lines.pop() || '';
231
+ for (const line of lines) {
232
+ if (line.startsWith('data: ')) {
233
+ try {
234
+ const data = JSON.parse(line.slice(6));
235
+ // Handle error events
236
+ if (data.type === 'error') {
237
+ throw new Error(data.error || 'Stream error');
238
+ }
239
+ // Yield ConversationMessage objects
240
+ if (data.id) {
241
+ yield data;
242
+ }
243
+ }
244
+ catch (e) {
245
+ console.error('[Widget API Client] Failed to parse SSE data:', line, e);
246
+ throw e;
247
+ }
248
+ }
249
+ }
250
+ }
251
+ }
252
+ finally {
253
+ reader.releaseLock();
254
+ }
255
+ }
256
+ /**
257
+ * Stream agent message responses with tool execution
258
+ * Handles streaming events from backend and yields ConversationMessage updates
259
+ */
260
+ async *sendAgentMessageStream(conversationId, message, fileIds) {
261
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
262
+ method: 'POST',
263
+ headers: {
264
+ 'Content-Type': 'application/json',
265
+ },
266
+ body: JSON.stringify({
267
+ conversationId: conversationId,
268
+ message,
269
+ fileIds,
270
+ timeZone: this.getTimeZone(),
271
+ }),
272
+ });
273
+ if (!response.ok) {
274
+ throw await buildApiError(response, 'Failed to send agent message');
275
+ }
276
+ if (!response.body) {
277
+ throw new Error('Response body is null');
278
+ }
279
+ const reader = response.body.getReader();
280
+ const decoder = new TextDecoder();
281
+ let buffer = '';
282
+ try {
283
+ while (true) {
284
+ const { done, value } = await reader.read();
285
+ if (done)
286
+ break;
287
+ buffer += decoder.decode(value, { stream: true });
288
+ const lines = buffer.split('\n');
289
+ buffer = lines.pop() || '';
290
+ for (const line of lines) {
291
+ if (line.startsWith('data: ')) {
292
+ try {
293
+ const data = JSON.parse(line.slice(6));
294
+ // Handle error events
295
+ if (data.type === 'error') {
296
+ throw new Error(data.error || 'Stream error');
297
+ }
298
+ // Yield ConversationMessage objects that come from the backend
299
+ // The backend yields full ConversationMessage objects during streaming
300
+ if (data.id) {
301
+ yield data;
302
+ }
303
+ }
304
+ catch (e) {
305
+ console.error('[Widget API Client] Failed to parse SSE data:', line, e);
306
+ throw e;
307
+ }
308
+ }
309
+ }
310
+ }
311
+ }
312
+ finally {
313
+ reader.releaseLock();
314
+ }
315
+ }
198
316
  /**
199
317
  * Submit feedback for a message
200
318
  */
@@ -261,8 +379,10 @@ function generateMessageId() {
261
379
  /**
262
380
  * Local Storage Utilities
263
381
  * Handles conversation persistence in browser localStorage
382
+ * Supports multiple conversations per widget with history
264
383
  */
265
384
  const STORAGE_PREFIX = 'ai-chat-widget';
385
+ const MAX_STORED_CONVERSATIONS = 20;
266
386
  /**
267
387
  * Generate a storage key for a widget
268
388
  */
@@ -270,33 +390,113 @@ function getStorageKey(widgetId) {
270
390
  return `${STORAGE_PREFIX}:${widgetId}`;
271
391
  }
272
392
  /**
273
- * Save conversation to localStorage
393
+ * Get widget storage data
274
394
  */
275
- function saveConversation(widgetId, conversationId, messages) {
395
+ function getWidgetStorage(widgetId) {
396
+ try {
397
+ const key = getStorageKey(widgetId);
398
+ const data = localStorage.getItem(key);
399
+ if (!data) {
400
+ return { activeConversationId: null, conversations: {}, history: [] };
401
+ }
402
+ const parsed = JSON.parse(data);
403
+ // Handle legacy format (single conversation)
404
+ if (parsed.conversationId && parsed.messages) {
405
+ const legacy = parsed;
406
+ return {
407
+ activeConversationId: legacy.conversationId,
408
+ conversations: { [legacy.conversationId]: legacy },
409
+ history: [{
410
+ id: legacy.conversationId,
411
+ preview: getConversationPreview(legacy.messages),
412
+ lastUpdated: legacy.lastUpdated,
413
+ messageCount: legacy.messages.length,
414
+ }],
415
+ };
416
+ }
417
+ return parsed;
418
+ }
419
+ catch (error) {
420
+ console.error('Failed to get widget storage:', error);
421
+ return { activeConversationId: null, conversations: {}, history: [] };
422
+ }
423
+ }
424
+ /**
425
+ * Save widget storage data
426
+ */
427
+ function setWidgetStorage(widgetId, storage) {
276
428
  try {
277
429
  const key = getStorageKey(widgetId);
278
- const data = {
430
+ localStorage.setItem(key, JSON.stringify(storage));
431
+ }
432
+ catch (error) {
433
+ console.error('Failed to save widget storage:', error);
434
+ }
435
+ }
436
+ /**
437
+ * Get preview text from messages
438
+ */
439
+ function getConversationPreview(messages) {
440
+ const firstUserMessage = messages.find(m => m.message.type === 'human');
441
+ if (firstUserMessage) {
442
+ return firstUserMessage.message.content.slice(0, 100);
443
+ }
444
+ return 'New conversation';
445
+ }
446
+ /**
447
+ * Save conversation to localStorage (updates both conversation and history)
448
+ */
449
+ function saveConversation(widgetId, conversationId, messages) {
450
+ try {
451
+ const storage = getWidgetStorage(widgetId);
452
+ const now = new Date().toISOString();
453
+ // Update conversation data
454
+ storage.conversations[conversationId] = {
279
455
  conversationId,
280
456
  messages,
281
- lastUpdated: new Date().toISOString(),
457
+ lastUpdated: now,
458
+ };
459
+ // Update active conversation
460
+ storage.activeConversationId = conversationId;
461
+ // Update history entry
462
+ const existingIndex = storage.history.findIndex(h => h.id === conversationId);
463
+ const historyEntry = {
464
+ id: conversationId,
465
+ preview: getConversationPreview(messages),
466
+ lastUpdated: now,
467
+ messageCount: messages.length,
282
468
  };
283
- localStorage.setItem(key, JSON.stringify(data));
469
+ if (existingIndex >= 0) {
470
+ storage.history[existingIndex] = historyEntry;
471
+ }
472
+ else {
473
+ storage.history.unshift(historyEntry);
474
+ }
475
+ // Sort by lastUpdated (most recent first)
476
+ storage.history.sort((a, b) => new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime());
477
+ // Limit stored conversations
478
+ if (storage.history.length > MAX_STORED_CONVERSATIONS) {
479
+ const toRemove = storage.history.slice(MAX_STORED_CONVERSATIONS);
480
+ storage.history = storage.history.slice(0, MAX_STORED_CONVERSATIONS);
481
+ toRemove.forEach(entry => {
482
+ delete storage.conversations[entry.id];
483
+ });
484
+ }
485
+ setWidgetStorage(widgetId, storage);
284
486
  }
285
487
  catch (error) {
286
488
  console.error('Failed to save conversation:', error);
287
489
  }
288
490
  }
289
491
  /**
290
- * Load conversation from localStorage
492
+ * Load active conversation from localStorage (legacy compatibility)
291
493
  */
292
494
  function loadConversation(widgetId) {
293
495
  try {
294
- const key = getStorageKey(widgetId);
295
- const data = localStorage.getItem(key);
296
- if (!data)
496
+ const storage = getWidgetStorage(widgetId);
497
+ if (!storage.activeConversationId)
297
498
  return null;
298
- const parsed = JSON.parse(data);
299
- return parsed;
499
+ return storage.conversations[storage.activeConversationId] || null;
300
500
  }
301
501
  catch (error) {
302
502
  console.error('Failed to load conversation:', error);
@@ -304,12 +504,52 @@ function loadConversation(widgetId) {
304
504
  }
305
505
  }
306
506
  /**
307
- * Clear conversation from localStorage
507
+ * Load a specific conversation by ID
508
+ */
509
+ function loadConversationById(widgetId, conversationId) {
510
+ try {
511
+ const storage = getWidgetStorage(widgetId);
512
+ return storage.conversations[conversationId] || null;
513
+ }
514
+ catch (error) {
515
+ console.error('Failed to load conversation by ID:', error);
516
+ return null;
517
+ }
518
+ }
519
+ /**
520
+ * Get conversation history list
521
+ */
522
+ function getConversationHistory(widgetId) {
523
+ try {
524
+ const storage = getWidgetStorage(widgetId);
525
+ return storage.history;
526
+ }
527
+ catch (error) {
528
+ console.error('Failed to get conversation history:', error);
529
+ return [];
530
+ }
531
+ }
532
+ /**
533
+ * Set active conversation
534
+ */
535
+ function setActiveConversation(widgetId, conversationId) {
536
+ try {
537
+ const storage = getWidgetStorage(widgetId);
538
+ storage.activeConversationId = conversationId;
539
+ setWidgetStorage(widgetId, storage);
540
+ }
541
+ catch (error) {
542
+ console.error('Failed to set active conversation:', error);
543
+ }
544
+ }
545
+ /**
546
+ * Clear current conversation (start fresh, but keep history)
308
547
  */
309
548
  function clearConversation(widgetId) {
310
549
  try {
311
- const key = getStorageKey(widgetId);
312
- localStorage.removeItem(key);
550
+ const storage = getWidgetStorage(widgetId);
551
+ storage.activeConversationId = null;
552
+ setWidgetStorage(widgetId, storage);
313
553
  }
314
554
  catch (error) {
315
555
  console.error('Failed to clear conversation:', error);
@@ -406,6 +646,8 @@ function useChat(options) {
406
646
  conversationId: '', // Will be set after loading conversation
407
647
  config: null,
408
648
  });
649
+ // Chat history state
650
+ const [conversations, setConversations] = react.useState([]);
409
651
  const apiClient = react.useRef(new WidgetApiClient({ widgetId, apiUrl }));
410
652
  // Load configuration on mount and hydrate with existing conversation if available
411
653
  react.useEffect(() => {
@@ -418,7 +660,7 @@ function useChat(options) {
418
660
  console.log('[useChat] Config fetched successfully:', {
419
661
  hasAppearance: !!config.appearance,
420
662
  });
421
- const persistConversation = config.behavior.persistConversation ?? true;
663
+ const persistConversation = config.settings.persistConversation ?? true;
422
664
  let conversationId = '';
423
665
  let messages = [];
424
666
  if (persistConversation && isStorageAvailable()) {
@@ -466,14 +708,14 @@ function useChat(options) {
466
708
  }, [widgetId, apiUrl, onError]);
467
709
  // Save conversation when messages change
468
710
  react.useEffect(() => {
469
- const persistConversation = state.config?.behavior.persistConversation ?? true;
711
+ const persistConversation = state.config?.settings.persistConversation ?? true;
470
712
  if (persistConversation &&
471
713
  isStorageAvailable() &&
472
714
  state.messages.length > 0 &&
473
715
  state.conversationId) {
474
716
  saveConversation(widgetId, state.conversationId, state.messages);
475
717
  }
476
- }, [widgetId, state.messages, state.conversationId, state.config?.behavior.persistConversation]);
718
+ }, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
477
719
  /**
478
720
  * Send a message
479
721
  */
@@ -495,8 +737,8 @@ function useChat(options) {
495
737
  setState(prev => ({
496
738
  ...prev,
497
739
  messages: [...prev.messages, userMessage],
498
- isLoading: true,
499
- isTyping: true,
740
+ isLoading: false, // Don't show loading, will show typing when stream starts
741
+ isTyping: true, // Show typing indicator immediately
500
742
  error: null,
501
743
  }));
502
744
  onMessage?.(userMessage);
@@ -542,71 +784,56 @@ function useChat(options) {
542
784
  }
543
785
  // Determine if widget has actions (use agent endpoint)
544
786
  const useAgent = state.config?.behavior.agentic || (state.config?.actions && state.config.actions.length > 0);
545
- let response;
546
- if (useAgent) {
547
- // Use agent endpoint - returns ConversationMessage[]
548
- response = await apiClient.current.sendAgentMessage(conversationId, trimmedContent, fileIds);
549
- }
550
- else {
551
- // Use standard chat endpoint
552
- response = await apiClient.current.sendMessage(conversationId, trimmedContent, fileIds);
553
- }
554
- // Both endpoints now return ConversationMessage[] array (FULL conversation)
555
- if (Array.isArray(response)) {
556
- // Response is already ConversationMessage[]
557
- const allMessages = response;
558
- // Find new messages (those not in current state)
559
- const existingIds = new Set(state.messages.map(m => m.id));
560
- const newMessages = allMessages.filter(msg => !existingIds.has(msg.id));
561
- setState(prev => ({
562
- ...prev,
563
- messages: allMessages, // Replace with full conversation
564
- isLoading: false,
565
- isTyping: false,
566
- }));
567
- // Only notify about new messages
568
- newMessages.forEach(msg => onMessage?.(msg));
569
- }
570
- else if (response.type === 'error') {
571
- // Error response from agent
572
- const errorContent = response.message || response.error || 'An error occurred';
573
- const errorMessage = {
574
- id: response.message_id || generateMessageId(),
575
- message: {
576
- type: 'ai',
577
- content: `⚠️ ${errorContent}`,
578
- },
579
- timestamp: response.timestamp || new Date().toISOString(),
580
- sources: [],
581
- };
582
- setState(prev => ({
583
- ...prev,
584
- messages: [...prev.messages, errorMessage],
585
- isLoading: false,
586
- isTyping: false,
587
- error: errorContent,
588
- }));
589
- onMessage?.(errorMessage);
787
+ // Stream the response
788
+ let lastStreamedMessage = null;
789
+ const stream = useAgent
790
+ ? apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds)
791
+ : apiClient.current.sendMessageStream(conversationId, trimmedContent, fileIds);
792
+ for await (const message of stream) {
793
+ lastStreamedMessage = message;
794
+ // Update state with streamed message
795
+ setState(prev => {
796
+ const existingIndex = prev.messages.findIndex(m => m.id === message.id);
797
+ if (existingIndex >= 0) {
798
+ // Update existing streaming message
799
+ const newMessages = [...prev.messages];
800
+ newMessages[existingIndex] = message;
801
+ // Show typing indicator if:
802
+ // 1. Message is streaming AND has no content (waiting for first token or after tool call)
803
+ // 2. Message is a tool execution (shows loading spinner on the tool)
804
+ const isAIMessage = message.message.type === 'ai';
805
+ const hasContent = isAIMessage && message.message.content.trim().length > 0;
806
+ const isToolExecuting = message.toolExecuting !== undefined;
807
+ return {
808
+ ...prev,
809
+ messages: newMessages,
810
+ isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
811
+ isLoading: false,
812
+ };
813
+ }
814
+ else {
815
+ // Add new streaming message
816
+ const isAIMessage = message.message.type === 'ai';
817
+ const hasContent = isAIMessage && message.message.content.trim().length > 0;
818
+ const isToolExecuting = message.toolExecuting !== undefined;
819
+ return {
820
+ ...prev,
821
+ messages: [...prev.messages, message],
822
+ isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
823
+ isLoading: false,
824
+ };
825
+ }
826
+ });
590
827
  }
591
- else {
592
- // Standard message response (type: 'message' or undefined)
593
- const messageContent = response.content || response.message || '';
594
- const assistantMessage = {
595
- id: response.message_id || response.messageId || generateMessageId(),
596
- message: {
597
- type: 'ai',
598
- content: messageContent,
599
- },
600
- timestamp: response.timestamp || new Date().toISOString(),
601
- sources: response.sources || [],
602
- };
603
- setState(prev => ({
604
- ...prev,
605
- messages: [...prev.messages, assistantMessage],
606
- isLoading: false,
607
- isTyping: false,
608
- }));
609
- onMessage?.(assistantMessage);
828
+ // Stream completed - finalize state
829
+ setState(prev => ({
830
+ ...prev,
831
+ isLoading: false,
832
+ isTyping: false,
833
+ }));
834
+ // Notify about final message
835
+ if (lastStreamedMessage) {
836
+ onMessage?.(lastStreamedMessage);
610
837
  }
611
838
  }
612
839
  catch (error) {
@@ -664,11 +891,11 @@ function useChat(options) {
664
891
  conversationId: '',
665
892
  error: null,
666
893
  }));
667
- const persistConversation = state.config?.behavior.persistConversation ?? true;
894
+ const persistConversation = state.config?.settings.persistConversation ?? true;
668
895
  if (persistConversation && isStorageAvailable()) {
669
896
  clearConversation(widgetId);
670
897
  }
671
- }, [widgetId, state.config?.behavior.persistConversation]);
898
+ }, [widgetId, state.config?.settings.persistConversation]);
672
899
  /**
673
900
  * Submit feedback for a message
674
901
  */
@@ -691,6 +918,78 @@ function useChat(options) {
691
918
  onError?.(err);
692
919
  }
693
920
  }, [state.conversationId, onError]);
921
+ /**
922
+ * Load conversation history list from localStorage
923
+ */
924
+ const loadConversations = react.useCallback(() => {
925
+ const persistConversation = state.config?.settings.persistConversation ?? true;
926
+ if (!persistConversation || !isStorageAvailable()) {
927
+ setConversations([]);
928
+ return;
929
+ }
930
+ const history = getConversationHistory(widgetId);
931
+ setConversations(history.map(entry => ({
932
+ id: entry.id,
933
+ preview: entry.preview,
934
+ lastMessageAt: entry.lastUpdated,
935
+ messageCount: entry.messageCount,
936
+ startedAt: entry.lastUpdated,
937
+ })));
938
+ }, [widgetId, state.config?.settings.persistConversation]);
939
+ /**
940
+ * Switch to a different conversation (from localStorage first, then fetch from server if needed)
941
+ */
942
+ const switchConversation = react.useCallback(async (conversationId) => {
943
+ const persistConversation = state.config?.settings.persistConversation ?? true;
944
+ // First try to load from localStorage
945
+ if (persistConversation && isStorageAvailable()) {
946
+ const stored = loadConversationById(widgetId, conversationId);
947
+ if (stored) {
948
+ setState(prev => ({
949
+ ...prev,
950
+ conversationId: stored.conversationId,
951
+ messages: stored.messages,
952
+ }));
953
+ setActiveConversation(widgetId, conversationId);
954
+ return;
955
+ }
956
+ }
957
+ // If not in localStorage, fetch from server
958
+ setState(prev => ({ ...prev, isLoading: true, error: null }));
959
+ try {
960
+ const conversation = await apiClient.current.getOrCreateConversation(conversationId);
961
+ setState(prev => ({
962
+ ...prev,
963
+ conversationId: conversation.id,
964
+ messages: conversation.messages,
965
+ isLoading: false,
966
+ }));
967
+ // Save to local storage
968
+ if (persistConversation && isStorageAvailable()) {
969
+ saveConversation(widgetId, conversation.id, conversation.messages);
970
+ }
971
+ }
972
+ catch (error) {
973
+ const errorInfo = deriveErrorInfo(error);
974
+ setState(prev => ({ ...prev, isLoading: false, error: errorInfo.message }));
975
+ }
976
+ }, [widgetId, state.config?.settings.persistConversation]);
977
+ /**
978
+ * Start a new conversation (keeps history)
979
+ */
980
+ const startNewConversation = react.useCallback(() => {
981
+ setState(prev => ({
982
+ ...prev,
983
+ messages: [],
984
+ conversationId: '',
985
+ error: null,
986
+ }));
987
+ // Clear active conversation but keep history
988
+ const persistConversation = state.config?.settings.persistConversation ?? true;
989
+ if (persistConversation && isStorageAvailable()) {
990
+ clearConversation(widgetId);
991
+ }
992
+ }, [widgetId, state.config?.settings.persistConversation]);
694
993
  return {
695
994
  messages: state.messages,
696
995
  isLoading: state.isLoading,
@@ -701,6 +1000,11 @@ function useChat(options) {
701
1000
  sendMessage,
702
1001
  clearMessages,
703
1002
  submitFeedback,
1003
+ // Chat history features
1004
+ conversations,
1005
+ loadConversations,
1006
+ switchConversation,
1007
+ startNewConversation,
704
1008
  };
705
1009
  }
706
1010
 
@@ -21393,7 +21697,7 @@ const Sources = ({ sources, displayMode = 'with-score' }) => {
21393
21697
  return (jsxRuntime.jsxs("div", { className: "ai-chat-sources", children: [jsxRuntime.jsxs("button", { className: "ai-chat-sources-toggle", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, children: [jsxRuntime.jsx("span", { className: "ai-chat-sources-icon", children: isExpanded ? '▼' : '▶' }), jsxRuntime.jsxs("span", { className: "ai-chat-sources-title", children: [sources.length, " source", sources.length > 1 ? 's' : ''] })] }), isExpanded && displayMode !== 'minimal' && (jsxRuntime.jsx("div", { className: "ai-chat-sources-list", children: sources.map((source, index) => (jsxRuntime.jsxs("div", { className: "ai-chat-source-item", children: [jsxRuntime.jsxs("div", { className: "ai-chat-source-number", children: [index + 1, "."] }), jsxRuntime.jsxs("div", { className: "ai-chat-source-details", children: [displayMode === 'with-score' && source.score && (jsxRuntime.jsxs("div", { className: "ai-chat-source-score", children: ["Score: ", (source.score * 100).toFixed(0), "%"] })), (displayMode === 'with-content' || displayMode === 'full') && source.doc.pageContent && (jsxRuntime.jsxs("div", { className: "ai-chat-source-content", children: [source.doc.pageContent.substring(0, 100), source.doc.pageContent.length > 100 ? '...' : ''] })), displayMode === 'full' && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [source.score && (jsxRuntime.jsxs("div", { className: "ai-chat-source-score", children: ["Score: ", (source.score * 100).toFixed(0), "%"] })), source.doc.metadata && Object.keys(source.doc.metadata).length > 0 && (jsxRuntime.jsx("div", { className: "ai-chat-source-metadata", children: Object.entries(source.doc.metadata).map(([key, value]) => (jsxRuntime.jsxs("span", { className: "ai-chat-source-meta-item", children: [key, ": ", String(value)] }, key))) }))] }))] })] }, `${source.kbId}-${source.doc.id}-${index}`))) }))] }));
21394
21698
  };
21395
21699
 
21396
- const Message = ({ message, showTimestamp = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', onFeedback, toolCallNameById, }) => {
21700
+ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', onFeedback, }) => {
21397
21701
  const formatTime = (timestamp) => {
21398
21702
  const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
21399
21703
  return date.toLocaleTimeString('en-US', {
@@ -21402,72 +21706,84 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
21402
21706
  hour12: true,
21403
21707
  });
21404
21708
  };
21405
- // Map message type to CSS class
21406
- const messageClass = message.message.type === 'human' ? 'user' :
21407
- message.message.type === 'ai' ? 'assistant' :
21408
- message.message.type === 'system' ? 'system' : 'tool';
21409
- const isAssistant = message.message.type === 'ai';
21410
- const isSystem = message.message.type === 'system';
21411
- const isTool = message.message.type === 'tool';
21412
- const isHuman = message.message.type === 'human';
21413
- const userMessage = isHuman ? message.message.content.split('--- File Content ---')[0] : '';
21414
- const aiContent = isAssistant ? (message.message.content || '') : '';
21415
- const aiHasContent = isAssistant ? aiContent.trim().length > 0 : false;
21416
- const renderAssistant = () => {
21417
- // Only render assistant bubble if there's textual content
21418
- return jsxRuntime.jsx(Markdown, { children: aiContent });
21419
- };
21420
21709
  const formatToolName = (name) => {
21421
- // Remove common prefixes like "action_" or "tool_"
21422
- let formatted = name.replace(/^(action_|tool_)/, '');
21423
- // Convert snake_case to Title Case
21424
- formatted = formatted
21710
+ return name
21711
+ .replace(/^(action_|tool_)/, '')
21425
21712
  .split('_')
21426
21713
  .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
21427
21714
  .join(' ');
21428
- return formatted;
21429
21715
  };
21430
- const renderTool = () => {
21431
- const tool = message.message;
21432
- const rawToolName = (toolCallNameById && toolCallNameById[tool.tool_call_id]) || 'Tool';
21433
- const displayName = formatToolName(rawToolName);
21434
- return (jsxRuntime.jsxs("div", { className: "ai-chat-tool-message", title: rawToolName, children: [jsxRuntime.jsx("span", { className: "tool-finished", children: jsxRuntime.jsx("span", { className: "tool-check", children: "\u2713" }) }), jsxRuntime.jsx("span", { className: "tool-name", children: displayName })] }));
21435
- };
21436
- // If assistant message has no content (e.g., only started a tool), render nothing at all
21437
- if (isAssistant && !aiHasContent) {
21438
- return null;
21716
+ const SpinnerIcon = () => (jsxRuntime.jsx("svg", { className: "ai-chat-tool-spinner", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) }));
21717
+ const CheckIcon = () => (jsxRuntime.jsx("svg", { className: "ai-chat-tool-check", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
21718
+ const ErrorIcon = () => (jsxRuntime.jsx("svg", { className: "ai-chat-tool-error", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }));
21719
+ const msgType = message.message.type;
21720
+ const isError = message.isError || false;
21721
+ const isTool = msgType === 'tool';
21722
+ const isAssistant = msgType === 'ai';
21723
+ const isSystem = msgType === 'system';
21724
+ const isHuman = msgType === 'human';
21725
+ // Tool message rendering - show as a minimal pill
21726
+ if (isTool) {
21727
+ // Get tool name from toolExecuting (during execution) or message.name (persisted)
21728
+ const toolName = message.toolExecuting || message.message.name || 'Tool';
21729
+ const hasError = isError;
21730
+ return (jsxRuntime.jsx("div", { className: "ai-chat-message tool", children: jsxRuntime.jsxs("div", { className: `ai-chat-tool-message ${hasError ? 'error' : ''}`, title: toolName, children: [message.isStreaming ? (jsxRuntime.jsx(SpinnerIcon, {})) : hasError ? (jsxRuntime.jsx(ErrorIcon, {})) : (jsxRuntime.jsx(CheckIcon, {})), jsxRuntime.jsx("span", { className: "tool-name", children: formatToolName(toolName) })] }) }));
21731
+ }
21732
+ // AI message rendering
21733
+ if (isAssistant) {
21734
+ const aiContent = message.message.content || '';
21735
+ const hasContent = aiContent.trim().length > 0;
21736
+ if (!hasContent)
21737
+ return null;
21738
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxRuntime.jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxRuntime.jsxs("div", { className: "ai-chat-error-indicator", children: [jsxRuntime.jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsxRuntime.jsx("span", { className: "error-text", children: "Error" })] })), jsxRuntime.jsx(Markdown, { children: aiContent })] }), showTimestamp && (jsxRuntime.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntime.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] })), showSources && message.sources?.length > 0 && (jsxRuntime.jsx(Sources, { sources: message.sources, displayMode: sourceDisplayMode }))] }));
21739
+ }
21740
+ // System message rendering
21741
+ if (isSystem) {
21742
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-message system", children: [jsxRuntime.jsx("div", { className: "ai-chat-message-content", children: jsxRuntime.jsxs("div", { className: "ai-chat-system-message", children: [jsxRuntime.jsx("span", { className: "system-icon", children: "\u2139\uFE0F" }), message.message.content] }) }), showTimestamp && (jsxRuntime.jsx("div", { className: "ai-chat-message-meta", children: jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }) }))] }));
21439
21743
  }
21440
- const showTimestampForThis = showTimestamp && !isTool && !(isAssistant && !aiHasContent);
21441
- return (jsxRuntime.jsxs("div", { className: `ai-chat-message ${messageClass}`, children: [isTool ? (
21442
- // Render tool call completion as a standalone, non-bubble event
21443
- renderTool()) : (jsxRuntime.jsx("div", { className: "ai-chat-message-content", children: isAssistant ? (renderAssistant()) : isSystem ? (jsxRuntime.jsxs("div", { className: "ai-chat-system-message", children: [jsxRuntime.jsx("span", { className: "system-icon", children: "\u2139\uFE0F" }), message.message.content] })) : (userMessage) })), showTimestampForThis && (jsxRuntime.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), isAssistant && aiHasContent && enableFeedback && onFeedback && (jsxRuntime.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] })), isAssistant && aiHasContent && showSources && message.sources && message.sources.length > 0 && (jsxRuntime.jsx(Sources, { sources: message.sources, displayMode: sourceDisplayMode }))] }));
21744
+ // Human message rendering
21745
+ if (isHuman) {
21746
+ const userContent = message.message.content.split('--- File Content ---')[0];
21747
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-message user", children: [jsxRuntime.jsx("div", { className: "ai-chat-message-content", children: userContent }), showTimestamp && (jsxRuntime.jsx("div", { className: "ai-chat-message-meta", children: jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }) }))] }));
21748
+ }
21749
+ return null;
21444
21750
  };
21445
21751
 
21446
21752
  const TypingIndicator = () => {
21447
21753
  return (jsxRuntime.jsx("div", { className: "ai-chat-message assistant", children: jsxRuntime.jsxs("div", { className: "ai-chat-typing", children: [jsxRuntime.jsx("span", { className: "ai-chat-typing-dot" }), jsxRuntime.jsx("span", { className: "ai-chat-typing-dot" }), jsxRuntime.jsx("span", { className: "ai-chat-typing-dot" })] }) }));
21448
21754
  };
21449
21755
 
21450
- const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', welcomeTitle, welcomeMessage, onFeedback, }) => {
21756
+ const SuggestedQuestions = ({ questions, onQuestionClick, }) => {
21757
+ if (!questions || questions.length === 0) {
21758
+ return null;
21759
+ }
21760
+ // Filter out empty questions
21761
+ const validQuestions = questions.filter(q => q && q.trim());
21762
+ if (validQuestions.length === 0) {
21763
+ return null;
21764
+ }
21765
+ return (jsxRuntime.jsx("div", { className: "ai-chat-suggested-questions", children: jsxRuntime.jsx("div", { className: "ai-chat-suggested-questions-list", children: validQuestions.slice(0, 5).map((question, index) => (jsxRuntime.jsx("button", { className: "ai-chat-suggested-question", onClick: () => onQuestionClick(question), type: "button", children: jsxRuntime.jsx("span", { className: "ai-chat-suggested-question-text", children: question }) }, index))) }) }));
21766
+ };
21767
+
21768
+ const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', welcomeTitle, welcomeMessage, suggestedQuestions, onSuggestedQuestionClick, onFeedback, }) => {
21769
+ const containerRef = react.useRef(null);
21451
21770
  const messagesEndRef = react.useRef(null);
21452
- // Auto-scroll to bottom when new messages arrive
21771
+ // Auto-scroll to bottom only on initial mount/load
21453
21772
  react.useEffect(() => {
21454
- messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
21455
- }, [messages, isTyping]);
21456
- // Build a map from tool_call_id -> tool name from AI messages
21457
- const toolCallNameById = react.useMemo(() => {
21458
- const map = {};
21459
- for (const m of messages) {
21460
- if (m.message.type === 'ai' && Array.isArray(m.message.tool_calls)) {
21461
- for (const tc of m.message.tool_calls) {
21462
- if (tc?.id && tc?.name) {
21463
- map[tc.id] = tc.name;
21464
- }
21465
- }
21466
- }
21773
+ const container = containerRef.current;
21774
+ if (!container)
21775
+ return;
21776
+ // Only scroll if content actually overflows AND the user is near the bottom.
21777
+ // This prevents the "first message" case from being pushed to the very bottom
21778
+ // (which looks like a huge empty gap above the first user message).
21779
+ const overflow = container.scrollHeight - container.clientHeight;
21780
+ const isOverflowing = overflow > 20;
21781
+ const nearBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 80;
21782
+ if (isOverflowing && nearBottom) {
21783
+ messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
21467
21784
  }
21468
- return map;
21469
- }, [messages]);
21470
- return (jsxRuntime.jsxs("div", { className: "ai-chat-messages", role: "log", "aria-live": "polite", "aria-atomic": "false", children: [messages.length === 0 && (welcomeTitle || welcomeMessage) && (jsxRuntime.jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && (jsxRuntime.jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle })), welcomeMessage && (jsxRuntime.jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage }))] })), messages.map((message) => (jsxRuntime.jsx(Message, { message: message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, showSources: showSources, sourceDisplayMode: sourceDisplayMode, toolCallNameById: toolCallNameById, onFeedback: onFeedback }, message.id))), isTyping && showTypingIndicator && jsxRuntime.jsx(TypingIndicator, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }));
21785
+ }, [messages, isTyping]);
21786
+ return (jsxRuntime.jsxs("div", { ref: containerRef, className: "ai-chat-messages", role: "log", "aria-live": "polite", "aria-atomic": "false", children: [(welcomeTitle || welcomeMessage) && (jsxRuntime.jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && (jsxRuntime.jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle })), welcomeMessage && (jsxRuntime.jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage })), messages.length === 0 && onSuggestedQuestionClick && suggestedQuestions && suggestedQuestions.length > 0 && (jsxRuntime.jsx(SuggestedQuestions, { questions: suggestedQuestions, onQuestionClick: onSuggestedQuestionClick }))] })), messages.map((message) => (jsxRuntime.jsx(Message, { message: message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, showSources: showSources, sourceDisplayMode: sourceDisplayMode, onFeedback: onFeedback }, message.id))), isTyping && showTypingIndicator && jsxRuntime.jsx(TypingIndicator, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }));
21471
21787
  };
21472
21788
 
21473
21789
  // Allowed file types
@@ -21555,58 +21871,98 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
21555
21871
  return (jsxRuntime.jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsxRuntime.jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => {
21556
21872
  const ext = getFileExtension(file.name);
21557
21873
  return (jsxRuntime.jsxs("div", { className: "ai-chat-file-item", children: [jsxRuntime.jsx("span", { className: "ai-chat-file-extension", children: ext }), jsxRuntime.jsxs("div", { className: "ai-chat-file-info", children: [jsxRuntime.jsx("span", { className: "ai-chat-file-name", children: file.name }), jsxRuntime.jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsxRuntime.jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index));
21558
- }) })), jsxRuntime.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(','), "aria-label": "File input" }), jsxRuntime.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) }) })] })), jsxRuntime.jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: handleChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 1, "aria-label": "Message input" }), jsxRuntime.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M22 2L11 13" }), jsxRuntime.jsx("path", { d: "M22 2L15 22L11 13L2 9L22 2Z" })] }) })] })] }));
21874
+ }) })), jsxRuntime.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(','), "aria-label": "File input" }), jsxRuntime.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M21.44 11.05l-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" }) }) })] })), jsxRuntime.jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: handleChange, onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 1, "aria-label": "Message input" }), jsxRuntime.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M12 19V5" }), jsxRuntime.jsx("path", { d: "M5 12l7-7 7 7" })] }) })] })] }));
21559
21875
  };
21560
21876
 
21561
- const ArrowIcon = () => (jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M5 12h14M12 5l7 7-7 7" }) }));
21562
- const SuggestedQuestions = ({ questions, onQuestionClick, }) => {
21563
- if (!questions || questions.length === 0) {
21564
- return null;
21565
- }
21566
- // Filter out empty questions
21567
- const validQuestions = questions.filter(q => q && q.trim());
21568
- if (validQuestions.length === 0) {
21569
- return null;
21570
- }
21571
- return (jsxRuntime.jsx("div", { className: "ai-chat-suggested-questions", children: jsxRuntime.jsx("div", { className: "ai-chat-suggested-questions-list", children: validQuestions.slice(0, 3).map((question, index) => (jsxRuntime.jsxs("button", { className: "ai-chat-suggested-question", onClick: () => onQuestionClick(question), type: "button", children: [jsxRuntime.jsx("span", { className: "ai-chat-suggested-question-text", children: question }), jsxRuntime.jsx("span", { className: "ai-chat-suggested-question-icon", children: jsxRuntime.jsx(ArrowIcon, {}) })] }, index))) }) }));
21572
- };
21573
-
21574
- const MinimizeIcon = () => (jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M5 12h14" }) }));
21575
- const ChatWindow = ({ messages, isLoading, isTyping, error, config, onSendMessage, onClose, onFeedback, }) => {
21877
+ const MenuIcon = () => (jsxRuntime.jsxs("svg", { width: "26", height: "26", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M4 10h16" }), jsxRuntime.jsx("path", { d: "M10 14h10" })] }));
21878
+ const PlusIcon = () => (jsxRuntime.jsxs("svg", { width: "26", height: "26", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M12 5v14" }), jsxRuntime.jsx("path", { d: "M5 12h14" })] }));
21879
+ const ChatWindow = ({ messages, isLoading, isTyping, error, config, onSendMessage, onClose: _onClose, onFeedback,
21880
+ // Chat history props (only active when persistConversation is true)
21881
+ conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, currentConversationId,
21882
+ // Override props for live preview
21883
+ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
21576
21884
  console.log('[ChatWindow] Rendering ChatWindow component');
21577
21885
  const appearance = config?.appearance;
21578
- const behavior = config?.behavior;
21579
- // Use simplified appearance fields
21886
+ const settings = config?.settings;
21887
+ // Check if chat history should be shown (requires both persistConversation AND showChatHistory)
21888
+ const canShowHistory = (settings?.persistConversation ?? true) && (settings?.showChatHistory ?? true);
21889
+ // Apply overrides for live preview (overrides take priority over saved config)
21580
21890
  const size = appearance?.size || 'medium';
21581
- const headerTitle = appearance?.headerTitle || 'AI Assistant';
21582
- const welcomeMessage = appearance?.welcomeMessage || '👋 Hi there! How can I assist you today?';
21583
- const inputPlaceholder = appearance?.placeholder || 'Ask me anything...';
21891
+ const headerTitle = headerTitleOverride ?? appearance?.headerTitle ?? 'AI Assistant';
21892
+ const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
21893
+ const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
21894
+ const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
21584
21895
  console.log('[ChatWindow] Appearance values:', {
21585
21896
  size,
21586
21897
  headerTitle,
21898
+ welcomeTitle,
21587
21899
  welcomeMessage,
21588
21900
  inputPlaceholder,
21589
21901
  });
21590
- // Track if suggested questions should be shown
21591
- const [showSuggestedQuestions, setShowSuggestedQuestions] = react.useState(true);
21592
- // Hide suggested questions after first user message
21593
- react.useEffect(() => {
21594
- const userMessages = messages.filter(m => m.message.type === 'human');
21595
- if (userMessages.length > 0) {
21596
- setShowSuggestedQuestions(false);
21902
+ // Track if history panel is open
21903
+ const [showHistory, setShowHistory] = react.useState(false);
21904
+ // History exit animation when starting a new chat from overview
21905
+ const [isHistoryExiting, setIsHistoryExiting] = react.useState(false);
21906
+ // Load conversations when history panel opens
21907
+ const handleOpenHistory = () => {
21908
+ setShowHistory(true);
21909
+ if (onLoadConversations) {
21910
+ onLoadConversations();
21911
+ }
21912
+ };
21913
+ // Handle conversation selection
21914
+ const handleSelectConversation = async (conversationId) => {
21915
+ if (onSwitchConversation) {
21916
+ await onSwitchConversation(conversationId);
21917
+ setShowHistory(false);
21597
21918
  }
21598
- }, [messages]);
21919
+ };
21920
+ const handleNewConversation = () => {
21921
+ if (!onStartNewConversation)
21922
+ return;
21923
+ onStartNewConversation();
21924
+ setShowHistory(false);
21925
+ };
21926
+ const handleSendFromOverview = (content) => {
21927
+ const trimmed = content.trim();
21928
+ if (!trimmed)
21929
+ return;
21930
+ if (!onStartNewConversation) {
21931
+ // Fallback: just go back to chat and send
21932
+ setShowHistory(false);
21933
+ onSendMessage(trimmed);
21934
+ return;
21935
+ }
21936
+ setIsHistoryExiting(true);
21937
+ window.setTimeout(() => {
21938
+ onStartNewConversation();
21939
+ setShowHistory(false);
21940
+ setIsHistoryExiting(false);
21941
+ onSendMessage(trimmed);
21942
+ }, 240);
21943
+ };
21599
21944
  // Check if message limit is reached
21600
- const maxMessages = behavior?.maxMessagesPerSession;
21945
+ const maxMessages = settings?.maxMessagesPerSession;
21601
21946
  const userMessageCount = messages.filter(m => m.message.type === 'human').length;
21602
21947
  const isLimitReached = maxMessages ? userMessageCount >= maxMessages : false;
21603
- // Handle suggested question click
21604
21948
  const handleQuestionClick = (question) => {
21605
- setShowSuggestedQuestions(false);
21606
21949
  onSendMessage(question);
21607
21950
  };
21608
- const hasMessages = messages.length > 0;
21609
- return (jsxRuntime.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntime.jsxs("div", { className: "ai-chat-header", children: [jsxRuntime.jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsxRuntime.jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsxRuntime.jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxRuntime.jsx("button", { className: "ai-chat-close-button", onClick: onClose, "aria-label": "Minimize chat", children: jsxRuntime.jsx(MinimizeIcon, {}) })] }), error && (jsxRuntime.jsx("div", { className: "ai-chat-error", role: "alert", children: error })), maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxRuntime.jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsxRuntime.jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), jsxRuntime.jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: behavior?.showTypingIndicator, showTimestamps: behavior?.showTimestamps, enableFeedback: behavior?.enableFeedback, showSources: behavior?.showSources, sourceDisplayMode: behavior?.sourceDisplayMode, welcomeMessage: welcomeMessage, onFeedback: onFeedback }), showSuggestedQuestions && !hasMessages && behavior?.suggestedQuestions && behavior.suggestedQuestions.length > 0 && (jsxRuntime.jsx(SuggestedQuestions, { questions: behavior.suggestedQuestions, onQuestionClick: handleQuestionClick })), jsxRuntime.jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : inputPlaceholder, disabled: isLoading || isLimitReached, enableFileUpload: behavior?.enableFileUpload })] }));
21951
+ // Format date for conversation list
21952
+ const formatDate = (dateString) => {
21953
+ const date = new Date(dateString);
21954
+ const now = new Date();
21955
+ const diffMs = now.getTime() - date.getTime();
21956
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
21957
+ if (diffDays === 0)
21958
+ return 'Today';
21959
+ if (diffDays === 1)
21960
+ return 'Yesterday';
21961
+ if (diffDays < 7)
21962
+ return `${diffDays} days ago`;
21963
+ return date.toLocaleDateString();
21964
+ };
21965
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntime.jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''}`, children: showHistory ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("div", { className: "ai-chat-title", children: headerTitle }), jsxRuntime.jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsxRuntime.jsx(PlusIcon, {}) })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsxRuntime.jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsxRuntime.jsx("div", { className: "ai-chat-title", children: headerTitle })] }), canShowHistory && (jsxRuntime.jsx("div", { className: "ai-chat-header-actions", children: jsxRuntime.jsx("button", { className: "ai-chat-close-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsxRuntime.jsx(MenuIcon, {}) }) }))] })) }), showHistory ? (jsxRuntime.jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsxRuntime.jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsxRuntime.jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsxRuntime.jsxs("button", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: [jsxRuntime.jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), jsxRuntime.jsxs("div", { className: "ai-chat-history-item-meta", children: [jsxRuntime.jsx("span", { children: formatDate(conv.lastMessageAt) }), jsxRuntime.jsxs("span", { children: [conv.messageCount, " messages"] })] })] }, conv.id))) })), jsxRuntime.jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [error && (jsxRuntime.jsx("div", { className: "ai-chat-error", role: "alert", children: error })), maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxRuntime.jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsxRuntime.jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), jsxRuntime.jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: settings?.showTypingIndicator, showTimestamps: settings?.showTimestamps, enableFeedback: settings?.enableFeedback, showSources: settings?.showSources, sourceDisplayMode: settings?.sourceDisplayMode, welcomeTitle: welcomeTitle || 'Welcome Message', welcomeMessage: welcomeMessage, suggestedQuestions: suggestedQuestionsOverride ?? settings?.suggestedQuestions, onSuggestedQuestionClick: handleQuestionClick, onFeedback: onFeedback }), jsxRuntime.jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : inputPlaceholder, disabled: isLoading || isLimitReached, enableFileUpload: settings?.enableFileUpload })] }))] }));
21610
21966
  };
21611
21967
 
21612
21968
  /**
@@ -21789,22 +22145,18 @@ function generateDarkPalette(accentColor) {
21789
22145
  * Generate all CSS custom properties for the widget
21790
22146
  */
21791
22147
  function generateThemeStyles(appearance, theme) {
21792
- const palette = theme === 'dark'
21793
- ? generateDarkPalette(appearance.accentColor)
21794
- : generateLightPalette(appearance.accentColor);
22148
+ const hasAccentColor = appearance.accentColor && appearance.accentColor.trim() !== '';
21795
22149
  // Liquid glass design - frosted glass with transparency
21796
22150
  const isLight = theme === 'light';
21797
- return {
22151
+ // Base styles that don't depend on accent color
22152
+ const styles = {
21798
22153
  // ========================================================================
21799
- // BUTTON (FAB) - Liquid Glass Style
22154
+ // BUTTON (FAB) - Base styles
21800
22155
  // ========================================================================
21801
- '--button-color': palette.accent,
21802
22156
  '--button-opacity': '1',
21803
22157
  '--button-size': '56px',
21804
- '--button-icon-color': palette.userBubbleText,
21805
22158
  '--button-border-radius': '50%',
21806
22159
  '--button-border-width': '0px',
21807
- '--button-border-color': palette.accent,
21808
22160
  '--button-border-opacity': '1',
21809
22161
  '--button-backdrop-blur': '20px',
21810
22162
  '--button-shadow': `0 4px 24px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1)`,
@@ -21827,7 +22179,6 @@ function generateThemeStyles(appearance, theme) {
21827
22179
  // ========================================================================
21828
22180
  '--header-background': 'transparent',
21829
22181
  '--header-opacity': '1',
21830
- '--header-text-color': palette.accent,
21831
22182
  '--header-border-bottom-width': '0px',
21832
22183
  '--header-border-bottom-color': 'transparent',
21833
22184
  '--header-border-bottom-opacity': '0',
@@ -21837,17 +22188,13 @@ function generateThemeStyles(appearance, theme) {
21837
22188
  // ========================================================================
21838
22189
  '--chat-background': 'transparent',
21839
22190
  '--chat-opacity': '1',
21840
- '--welcome-color': palette.text,
21841
- '--message-text-color': palette.text,
21842
22191
  // ========================================================================
21843
22192
  // MESSAGE BUBBLES - Glass style
21844
22193
  // ========================================================================
21845
- '--bubble-user-color': palette.userBubble,
21846
22194
  '--bubble-user-opacity': '1',
21847
- '--user-message-text': palette.userBubbleText,
21848
22195
  '--bubble-assistant-color': isLight ? 'rgba(255, 255, 255, 0.8)' : 'rgba(255, 255, 255, 0.1)',
21849
22196
  '--bubble-assistant-opacity': '1',
21850
- '--assistant-message-text': isLight ? palette.text : '#f0f0f0',
22197
+ '--assistant-message-text': isLight ? '#000000' : '#f0f0f0',
21851
22198
  '--bubble-border-radius': '20px',
21852
22199
  '--bubble-border-width': isLight ? '1px' : '1px',
21853
22200
  '--bubble-border-color': isLight ? 'rgba(0, 0, 0, 0.05)' : 'rgba(255, 255, 255, 0.08)',
@@ -21869,38 +22216,48 @@ function generateThemeStyles(appearance, theme) {
21869
22216
  '--input-border-color': isLight ? 'rgba(0, 0, 0, 0.08)' : 'rgba(255, 255, 255, 0.1)',
21870
22217
  '--input-border-opacity': '1',
21871
22218
  '--input-shadow': `inset 0 1px 3px rgba(0, 0, 0, 0.04), 0 2px 8px rgba(0, 0, 0, 0.04)`,
21872
- '--send-button-background': palette.accent,
21873
22219
  '--send-button-opacity': '1',
21874
22220
  '--send-button-border-radius': '50%',
21875
22221
  '--send-button-border-width': '0px',
21876
- '--send-button-border-color': palette.accent,
21877
22222
  '--send-button-border-opacity': '1',
21878
22223
  // ========================================================================
21879
22224
  // HOVER STATES
21880
22225
  // ========================================================================
21881
22226
  '--hover-button-scale': '1.08',
21882
22227
  '--hover-button-opacity': '1',
21883
- '--hover-input-border-color': palette.accent,
21884
22228
  '--hover-send-button-opacity': '1',
21885
22229
  '--hover-close-button-opacity': '1',
21886
22230
  // ========================================================================
21887
- // ACTIVE STATES
21888
- // ========================================================================
21889
- '--active-input-border-color': palette.accent,
21890
- '--active-input-shadow': `0 0 0 4px ${withAlpha(palette.accent, 0.15)}`,
21891
- // ========================================================================
21892
- // GENERAL
21893
- // ========================================================================
21894
- '--primary-color': palette.accent,
21895
- '--background-color': palette.background,
21896
- '--text-color': palette.text,
21897
- '--border-color': palette.border,
21898
- // ========================================================================
21899
22231
  // GLASS EFFECTS
21900
22232
  // ========================================================================
21901
22233
  '--glass-blur': '20px',
21902
22234
  '--glass-saturation': '180%',
21903
22235
  };
22236
+ // Only add accent-color-based styles if an accent color is provided
22237
+ if (hasAccentColor) {
22238
+ const palette = theme === 'dark'
22239
+ ? generateDarkPalette(appearance.accentColor)
22240
+ : generateLightPalette(appearance.accentColor);
22241
+ // Add accent color styles
22242
+ styles['--button-color'] = palette.accent;
22243
+ styles['--button-icon-color'] = palette.userBubbleText;
22244
+ styles['--button-border-color'] = palette.accent;
22245
+ styles['--header-text-color'] = palette.accent;
22246
+ styles['--welcome-color'] = palette.text;
22247
+ styles['--message-text-color'] = palette.text;
22248
+ styles['--bubble-user-color'] = palette.userBubble;
22249
+ styles['--user-message-text'] = palette.userBubbleText;
22250
+ styles['--send-button-background'] = palette.accent;
22251
+ styles['--send-button-border-color'] = palette.accent;
22252
+ styles['--hover-input-border-color'] = palette.accent;
22253
+ styles['--active-input-border-color'] = palette.accent;
22254
+ styles['--active-input-shadow'] = `0 0 0 4px ${withAlpha(palette.accent, 0.15)}`;
22255
+ styles['--primary-color'] = palette.accent;
22256
+ styles['--background-color'] = palette.background;
22257
+ styles['--text-color'] = palette.text;
22258
+ styles['--border-color'] = palette.border;
22259
+ }
22260
+ return styles;
21904
22261
  }
21905
22262
 
21906
22263
  /**
@@ -22011,7 +22368,7 @@ function styleInject(css, ref) {
22011
22368
  if ( ref === void 0 ) ref = {};
22012
22369
  var insertAt = ref.insertAt;
22013
22370
 
22014
- if (!css || typeof document === 'undefined') { return; }
22371
+ if (typeof document === 'undefined') { return; }
22015
22372
 
22016
22373
  var head = document.head || document.getElementsByTagName('head')[0];
22017
22374
  var style = document.createElement('style');
@@ -22034,10 +22391,7 @@ function styleInject(css, ref) {
22034
22391
  }
22035
22392
  }
22036
22393
 
22037
- var css_248z$1 = ".ai-chat-widget{--primary-color:#07f;--background-color:#fff;--text-color:#1f2937;--border-color:#e5e7eb;--user-message-bg:var(--primary-color);--user-message-text:#fff;--assistant-message-bg:#f3f4f6;--assistant-message-text:#374151;--input-bg:#fff;--input-border:#d1d5db;--shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);--shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);--button-color:#07f;--button-size:56px;--button-border-radius:28px;--button-border-width:0px;--button-border-color:#07f;--button-opacity:1;--button-backdrop-blur:0px;--button-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -2px rgba(0,0,0,.05);--card-background:#fff;--card-border-radius:16px;--card-border-width:0px;--card-border-color:#e5e7eb;--card-opacity:1;--card-backdrop-blur:0px;--card-shadow:0 25px 50px -12px rgba(0,0,0,.25);--header-background:#07f;--header-text-color:#fff;--header-font-size:18px;--header-border-bottom-width:0px;--header-border-bottom-color:#e5e7eb;--header-opacity:1;--header-backdrop-blur:0px;--chat-background:#fff;--chat-opacity:1;--chat-backdrop-blur:0px;--welcome-font-size:16px;--welcome-color:#1f2937;--welcome-opacity:1;--bubble-user-color:#07f;--bubble-assistant-color:#f3f4f6;--bubble-border-radius:16px;--bubble-border-width:0px;--bubble-border-color:#e5e7eb;--bubble-opacity:1;--typing-animation-color:#f3f4f6;--typing-animation-opacity:1;--typing-animation-border-width:0px;--typing-animation-border-color:#e5e7eb;--typing-animation-border-radius:16px;--footer-background:#fff;--footer-border-top-width:1px;--footer-border-top-color:#e5e7eb;--footer-opacity:1;--footer-backdrop-blur:0px;--input-background:#fff;--input-border-radius:24px;--input-border-width:1.5px;--input-border-color:#d1d5db;--input-opacity:1;--input-shadow:0 1px 2px 0 rgba(0,0,0,.05);--send-button-background:#07f;--send-button-border-radius:20px;--send-button-border-width:0px;--send-button-border-color:#07f;--send-button-opacity:1;--hover-button-scale:1.05;--hover-button-opacity:0.9;--hover-input-border-color:#9ca3af;--hover-send-button-opacity:0.85;--hover-close-button-opacity:1;--active-input-border-color:#07f;--active-input-shadow:0 0 0 3px rgba(0,119,255,.1);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget.dark{--background-color:#001d3d;--text-color:#f9fafb;--border-color:#374151;--assistant-message-bg:#036;--assistant-message-text:#e5e7eb;--input-bg:#002855;--input-border:#374151}.ai-chat-widget.dark .ai-chat-message.system .ai-chat-message-content{background-color:#78350f;color:#fef3c7}.ai-chat-widget.dark .ai-chat-message.tool .ai-chat-message-content{background-color:#1e3a8a;color:#dbeafe}.ai-chat-widget-container{font-size:14px;line-height:1.5;position:fixed;z-index:9999}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}.ai-chat-button{align-items:center;backdrop-filter:blur(var(--button-backdrop-blur));-webkit-backdrop-filter:blur(var(--button-backdrop-blur));background-color:var(--button-color);border:var(--button-border-width) solid var(--button-border-color);border-radius:var(--button-border-radius);box-shadow:var(--button-shadow);color:#fff;cursor:pointer;display:flex;height:var(--button-size);justify-content:center;opacity:var(--button-opacity);transition:all .3s cubic-bezier(.4,0,.2,1);width:var(--button-size)}.ai-chat-button:hover{opacity:.9}.ai-chat-button:active{opacity:.8}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;width:50%}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-window{border-radius:var(--card-border-radius);box-shadow:0 0 0 var(--card-border-width) var(--card-border-color-rgba,var(--card-border-color)),var(--card-shadow);display:flex;flex-direction:column;overflow:hidden;position:absolute}.ai-chat-window>*{position:relative;z-index:1}.ai-chat-window:before{backdrop-filter:blur(var(--card-backdrop-blur));-webkit-backdrop-filter:blur(var(--card-backdrop-blur));background-color:var(--card-background);border-radius:var(--card-border-radius);content:\"\";inset:0;opacity:var(--card-opacity);pointer-events:none;position:absolute;z-index:0}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 60px) + 16px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 60px) + 16px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 60px) + 16px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 60px) + 16px)}.ai-chat-button{z-index:1}.ai-chat-window{z-index:2}.ai-chat-window.size-small{height:500px;width:380px}.ai-chat-window.size-medium{height:650px;width:440px}.ai-chat-window.size-large{height:750px;width:520px}.ai-chat-logo{border-radius:50%;height:32px;object-fit:cover;width:32px}.ai-chat-messages::-webkit-scrollbar{width:6px}.ai-chat-messages::-webkit-scrollbar-track{background:transparent}.ai-chat-messages::-webkit-scrollbar-thumb{background:var(--border-color);border-radius:3px}.ai-chat-messages::-webkit-scrollbar-thumb:hover{background:var(--input-border)}.ai-chat-message{display:flex;flex-direction:column;gap:4px}.ai-chat-message.user{align-items:flex-end}.ai-chat-message.assistant{align-items:flex-start}.ai-chat-message.system{align-items:center}.ai-chat-message.tool{align-items:flex-start}.ai-chat-message-content{word-wrap:break-word;border:var(--bubble-border-width) solid var(--bubble-border-color);border-radius:var(--bubble-border-radius);font-size:15px;line-height:1.6;max-width:80%;opacity:var(--bubble-opacity);padding:12px 16px}.ai-chat-message.user .ai-chat-message-content{background-color:var(--bubble-user-color);border-bottom-right-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,.1);color:var(--user-message-text)}.ai-chat-message.assistant .ai-chat-message-content{background-color:var(--bubble-assistant-color,#f3f4f6);border:1px solid var(--bubble-border-color,rgba(0,0,0,.08));border-radius:var(--bubble-border-radius,16px);border-bottom-left-radius:4px;box-shadow:none;color:var(--assistant-message-text);max-width:85%;padding:12px 16px}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 12px}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content ol,.ai-chat-message.assistant .ai-chat-message-content ul{margin:8px 0 12px;padding-left:24px}.ai-chat-message.assistant .ai-chat-message-content li{line-height:1.5;margin:6px 0}.ai-chat-message.assistant .ai-chat-message-content li::marker{color:var(--primary-color,#07f)}.ai-chat-message.assistant .ai-chat-message-content ol li::marker{font-weight:600}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:600}.ai-chat-message.assistant .ai-chat-message-content em{font-style:italic}.ai-chat-message.assistant .ai-chat-message-content code{background-color:rgba(0,0,0,.06);border-radius:4px;font-family:SF Mono,Consolas,Monaco,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background-color:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background-color:rgba(0,0,0,.06);border-radius:8px;margin:8px 0 12px;overflow-x:auto;padding:12px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background-color:hsla(0,0%,100%,.08)}.ai-chat-message.assistant .ai-chat-message-content pre code{background-color:transparent;border-radius:0;padding:0}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--primary-color,#07f);color:var(--text-muted,#6b7280);margin:8px 0 12px;padding:4px 0 4px 12px}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--primary-color,#07f);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content a:hover{opacity:.8}.ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-message.assistant .ai-chat-message-content h2,.ai-chat-message.assistant .ai-chat-message-content h3,.ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-message.assistant .ai-chat-message-content h6{font-weight:600;line-height:1.3;margin:16px 0 8px}.ai-chat-message.assistant .ai-chat-message-content h1:first-child,.ai-chat-message.assistant .ai-chat-message-content h2:first-child,.ai-chat-message.assistant .ai-chat-message-content h3:first-child{margin-top:0}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-color,#e5e7eb);margin:12px 0}.ai-chat-message.system .ai-chat-message-content{background-color:#fef3c7;border-radius:8px;color:#92400e;font-size:12px;font-style:italic;max-width:90%;text-align:center}.ai-chat-message.tool .ai-chat-message-content{background-color:#dbeafe;border-bottom-left-radius:4px;color:#1e40af;font-family:Courier New,monospace;font-size:13px}.ai-chat-tool-indicators{display:flex;gap:6px;margin-top:6px}.tool-indicator{align-items:center;background:#dbeafe;border-radius:50%;color:#1e40af;display:inline-flex;height:18px;justify-content:center;overflow:hidden;position:relative;width:18px}.tool-indicator .icon{font-size:12px;line-height:1;z-index:1}.tool-indicator.started:after{animation:ai-spin 1s linear infinite;border:2px solid rgba(30,64,175,.25);border-radius:50%;border-top-color:#1e40af;content:\"\";inset:0;position:absolute}@keyframes ai-spin{to{transform:rotate(1turn)}}.ai-chat-tool-message{align-items:center;background:rgba(16,185,129,.1);border:1px solid rgba(16,185,129,.2);border-radius:20px;color:#059669;display:inline-flex;gap:8px;padding:8px 14px}.ai-chat-widget.dark .ai-chat-tool-message{background:rgba(16,185,129,.15);border-color:rgba(16,185,129,.25);color:#34d399}.tool-finished{align-items:center;display:inline-flex;font-size:14px;justify-content:center}.tool-finished .tool-icon{display:none}.tool-finished .tool-check{font-size:14px;font-weight:700}.tool-name{font-size:13px;font-weight:500}.ai-chat-message-timestamp{color:rgba(0,0,0,.6);filter:invert(1) grayscale(1) contrast(1.2);mix-blend-mode:difference;padding:0 4px}.ai-chat-welcome{align-items:center;color:var(--welcome-color);display:flex;flex-direction:column;justify-content:center;min-height:200px;opacity:var(--welcome-opacity);padding:60px 32px 40px;text-align:center}.ai-chat-welcome-title{color:var(--primary-color);font-size:28px;font-weight:700;letter-spacing:-.03em;margin-bottom:12px}.ai-chat-welcome-text{color:var(--assistant-message-text);font-size:16px;line-height:1.6;max-width:280px;opacity:.7}.ai-chat-typing{align-items:center;background-color:var(--assistant-message-bg);border-radius:12px;border-bottom-left-radius:4px;display:flex;gap:4px;max-width:80px;padding:10px 14px}.ai-chat-typing-dot{animation:typingBounce 1.4s infinite;background-color:#9ca3af;border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:nth-child(2){animation-delay:.2s}.ai-chat-typing-dot:nth-child(3){animation-delay:.4s}@keyframes typingBounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-8px)}}.ai-chat-file-button{align-items:center;background:none;border:none;border-radius:6px;color:var(--text-color);cursor:pointer;display:flex;justify-content:center;padding:8px;transition:background-color .2s}.ai-chat-file-button:hover:not(:disabled){background-color:rgba(0,0,0,.05)}.ai-chat-file-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:8px;padding:8px 12px}.ai-chat-file-item{align-items:center;background-color:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:12px;gap:8px;padding:6px 10px}.ai-chat-file-extension{background-color:var(--primary-color);border-radius:3px;color:#fff;display:inline-block;font-size:10px;font-weight:600;min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:500;max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:4px;transition:opacity .15s ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-message-attachments{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}.ai-chat-message-attachment{align-items:center;background-color:rgba(0,0,0,.08);border-radius:4px;display:inline-flex;font-size:11px;gap:4px;padding:3px 8px}.ai-chat-attachment-icon{font-size:12px}.ai-chat-attachment-ext{background-color:var(--primary-color);border-radius:2px;color:#fff;display:inline-block;font-size:9px;font-weight:600;padding:1px 4px;text-transform:uppercase}.ai-chat-attachment-name{max-width:120px;opacity:.8;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-sources{background-color:rgba(0,0,0,.02);border-radius:6px;font-size:12px;margin-top:8px;overflow:hidden}.ai-chat-sources-toggle{align-items:center;background:none;border:none;cursor:pointer;display:flex;gap:6px;padding:8px 10px;text-align:left;transition:background-color .2s;width:100%}.ai-chat-sources-toggle:hover{background-color:rgba(0,0,0,.03)}.ai-chat-sources-icon{color:var(--text-muted);font-size:10px;transition:transform .2s}.ai-chat-sources-title{color:var(--text-color);flex:1;font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-source-item{border-top:1px solid rgba(0,0,0,.05);color:#6b7280;display:flex;gap:8px;padding:8px 10px}.ai-chat-source-item:last-child{border-bottom:none}.ai-chat-source-number{color:var(--primary-color);flex-shrink:0;font-weight:600}.ai-chat-source-details{display:flex;flex:1;flex-direction:column;gap:4px}.ai-chat-source-score{color:#9ca3af;font-size:11px}.ai-chat-source-content{color:#6b7280;font-size:11px;font-style:italic;line-height:1.4}.ai-chat-source-metadata{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}.ai-chat-source-meta-item{background-color:rgba(0,0,0,.05);border-radius:3px;color:#6b7280;font-size:10px;padding:2px 6px}.ai-chat-message-meta{align-items:center;display:inline-flex;gap:6px;height:20px}.ai-chat-message-timestamp{color:#71717a;font-size:11px;line-height:1}.ai-chat-feedback{gap:0}.ai-chat-feedback,.ai-chat-feedback-button{align-items:center;display:inline-flex;height:20px}.ai-chat-feedback-button{background:none!important;border:none;border-radius:0;color:#71717a;cursor:pointer;justify-content:center;padding:0 4px;transition:color .15s ease}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:#52525b}.ai-chat-feedback-button:active:not(:disabled){opacity:.7}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--primary-color,#07f)}.ai-chat-feedback-submitted{align-items:center;animation:feedbackMorph .3s cubic-bezier(.34,1.56,.64,1);display:flex;gap:6px}.ai-chat-feedback-checkmark{animation:checkmarkPop .3s cubic-bezier(.34,1.56,.64,1);color:#10b981;font-size:16px;font-weight:700}.ai-chat-feedback-text{animation:textSlideIn .3s ease;color:#10b981;font-size:13px;font-weight:500}@keyframes feedbackMorph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes checkmarkPop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes textSlideIn{0%{opacity:0;transform:translateX(-10px)}to{opacity:1;transform:translateX(0)}}.ai-chat-error{align-items:flex-start;background-color:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.2);border-radius:12px;color:#ef4444;display:flex;font-size:14px;font-weight:500;gap:10px;line-height:1.5;margin:8px 16px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-error{background-color:rgba(239,68,68,.15);border-color:rgba(239,68,68,.25);color:#fca5a5}.ai-chat-error:before{align-items:center;background:rgba(239,68,68,.2);border-radius:50%;content:\"⚠\";display:flex;flex-shrink:0;font-size:14px;font-weight:700;height:20px;justify-content:center;width:20px}.ai-chat-widget.dark .ai-chat-error:before{background:rgba(239,68,68,.25)}.ai-chat-warning{background-color:rgba(245,158,11,.1);border:1px solid rgba(245,158,11,.2);border-radius:12px;color:#d97706;font-size:13px;margin:8px 16px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-warning{background-color:rgba(245,158,11,.15);border-color:rgba(245,158,11,.25);color:#fbbf24}.ai-chat-suggested-questions{bottom:80px;left:0;padding:0 20px 16px;position:absolute;right:0;z-index:5}.ai-chat-suggested-questions-list{display:flex;flex-direction:column;gap:8px}.ai-chat-suggested-question{align-items:center;background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:14px;box-shadow:0 1px 3px rgba(0,0,0,.04);color:#374151;cursor:pointer;display:flex;font-size:14px;font-weight:500;gap:12px;justify-content:space-between;padding:14px 16px;text-align:left;transition:all .15s ease;width:100%}.ai-chat-suggested-question:hover{background:#f9fafb;border-color:rgba(0,0,0,.12);box-shadow:0 2px 8px rgba(0,0,0,.06)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question-text{flex:1;line-height:1.4}.ai-chat-suggested-question-icon{color:var(--primary-color,#07f);flex-shrink:0;opacity:.7;transition:transform .15s ease,opacity .15s ease}.ai-chat-suggested-question:hover .ai-chat-suggested-question-icon{opacity:1;transform:translateX(3px)}@media (max-width:480px){.ai-chat-window{border-radius:0!important;bottom:0!important;height:100%!important;left:0!important;position:fixed!important;right:0!important;top:0!important;width:100%!important}.ai-chat-widget-container{bottom:20px!important;right:20px!important}.ai-chat-suggested-question{font-size:13px;padding:9px 10px}}.ai-chat-action-approval{background:linear-gradient(135deg,#07f,#001d3d);border-radius:16px;box-shadow:0 4px 12px rgba(0,119,255,.3);color:#fff;margin:16px;padding:16px}.ai-chat-action-approval-content{align-items:flex-start;display:flex;gap:12px;margin-bottom:16px}.ai-chat-action-approval-icon{align-items:center;background:hsla(0,0%,100%,.2);border-radius:8px;display:flex;flex-shrink:0;height:40px;justify-content:center;width:40px}.ai-chat-action-approval-text{flex:1}.ai-chat-action-approval-title{font-size:15px;font-weight:600;margin-bottom:4px}.ai-chat-action-approval-description{font-size:13px;line-height:1.4;opacity:.95}.ai-chat-action-approval-buttons{display:flex;gap:8px;justify-content:flex-end}.ai-chat-action-button{align-items:center;border:none;border-radius:8px;cursor:pointer;display:flex;font-family:inherit;font-size:14px;font-weight:500;gap:6px;padding:8px 16px;transition:all .2s ease}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.6}.ai-chat-action-button-reject{background:hsla(0,0%,100%,.2);color:#fff}.ai-chat-action-button-reject:hover:not(:disabled){background:hsla(0,0%,100%,.3)}.ai-chat-action-button-approve{background:#fff;color:#07f}.ai-chat-action-button-approve:hover:not(:disabled){background:#f0f0f0;box-shadow:0 2px 8px rgba(0,0,0,.15);transform:translateY(-1px)}.ai-chat-action-spinner{animation:ai-chat-spin .6s linear infinite;border:2px solid rgba(0,119,255,.3);border-radius:50%;border-top-color:#07f;display:inline-block;height:14px;width:14px}@keyframes ai-chat-spin{to{transform:rotate(1turn)}}";
22038
- styleInject(css_248z$1);
22039
-
22040
- var css_248z = ".ai-chat-widget{--spring-bounce:cubic-bezier(0.34,1.56,0.64,1);--spring-smooth:cubic-bezier(0.4,0,0.2,1);--spring-snappy:cubic-bezier(0.2,0,0,1);--duration-fast:0.2s;--duration-normal:0.35s;--duration-slow:0.5s}.ai-chat-button{align-items:center;background:var(--button-color,var(--primary-color,#07f));border:none;border-radius:50%;box-shadow:0 2px 8px rgba(0,0,0,.15);cursor:pointer;display:flex;height:48px;justify-content:center;overflow:hidden;position:relative;transition:opacity .15s ease;width:48px}.ai-chat-button:hover{opacity:.9}.ai-chat-button:active{opacity:.8}.ai-chat-button-svg{height:20px;transition:transform .15s ease;width:20px}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-window{animation:windowOpen var(--duration-slow) var(--spring-bounce);background:#fff;border:1px solid #e5e7eb;border-radius:16px;box-shadow:0 4px 24px rgba(0,0,0,.12),0 1px 3px rgba(0,0,0,.08);display:flex;flex-direction:column;overflow:hidden;position:absolute;transform-origin:bottom right}.ai-chat-widget.dark .ai-chat-window{background:#18181b;border-color:#27272a}@keyframes windowOpen{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}.ai-chat-window.closing{animation:windowClose var(--duration-normal) var(--spring-smooth) forwards}@keyframes windowClose{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}.ai-chat-header{align-items:center;background:#fff;border-bottom:1px solid #e5e7eb;display:flex;justify-content:space-between;padding:16px 20px;position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:#18181b;border-bottom-color:#27272a}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:12px}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:#18181b;font-size:15px;font-weight:600;letter-spacing:-.01em}.ai-chat-widget.dark .ai-chat-title{color:#fafafa}.ai-chat-close-button{align-items:center;background:transparent;border:none;border-radius:8px;color:#a1a1aa;cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all .15s ease;width:32px}.ai-chat-widget.dark .ai-chat-close-button{color:#71717a}.ai-chat-close-button:hover{background:#f4f4f5;color:#52525b}.ai-chat-widget.dark .ai-chat-close-button:hover{background:#27272a;color:#a1a1aa}.ai-chat-close-button:active{transform:scale(.95)}.ai-chat-messages{-webkit-overflow-scrolling:touch;background:#f4f4f5;display:flex;flex:1;flex-direction:column;gap:12px;overflow-x:hidden;overflow-y:auto;padding:16px 16px 90px;position:relative;scroll-behavior:smooth}.ai-chat-widget.dark .ai-chat-messages{background:#18181b}.ai-chat-messages::-webkit-scrollbar{width:4px}.ai-chat-messages::-webkit-scrollbar-track{background:transparent}.ai-chat-messages::-webkit-scrollbar-thumb{background:rgba(0,0,0,.15);border-radius:4px}.ai-chat-messages::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.25)}.ai-chat-message{animation:messageSlideIn var(--duration-normal) var(--spring-bounce);display:flex;flex-direction:column;gap:6px}@keyframes messageSlideIn{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}.ai-chat-message-content{word-wrap:break-word;border-radius:12px;font-size:14px;line-height:1.5;max-width:85%;padding:8px 14px}.ai-chat-message.user .ai-chat-message-content{background:var(--bubble-user-color,var(--primary-color,#07f));border-bottom-right-radius:4px;color:#fff;margin-left:auto}.ai-chat-message.assistant .ai-chat-message-content{background:#fff;border:1px solid #e5e7eb;border-bottom-left-radius:4px;color:#374151}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{background:#18181b;border-color:#27272a;color:#e4e4e7}.ai-chat-typing{align-items:center;animation:messageSlideIn var(--duration-normal) var(--spring-bounce);background:#fff;border:1px solid #e5e7eb;border-radius:12px;border-bottom-left-radius:4px;display:flex;gap:4px;max-width:64px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-typing{background:#18181b;border-color:#27272a}.ai-chat-typing-dot{animation:typingPulse 1.4s ease-in-out infinite;background:linear-gradient(135deg,var(--primary-color) 0,color-mix(in srgb,var(--primary-color) 70%,#000) 100%);border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:nth-child(2){animation-delay:.15s}.ai-chat-typing-dot:nth-child(3){animation-delay:.3s}@keyframes typingPulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-6px) scale(1.1)}}.ai-chat-input-container{background:transparent;bottom:0;left:0;padding:0 16px 16px;position:absolute;right:0;z-index:10}.ai-chat-input-container:before{background:linear-gradient(0deg,#f4f4f5 80%,transparent);bottom:0;content:\"\";height:48px;left:0;pointer-events:none;position:absolute;right:0;z-index:-1}.ai-chat-widget.dark .ai-chat-input-container:before{background:linear-gradient(0deg,#18181b 80%,transparent)}.ai-chat-input-wrapper{align-items:center;background:#f4f4f5;border:1px solid #e5e7eb;border-radius:9999px;display:flex;gap:0;padding:4px 4px 4px 16px;position:relative;transition:all .15s ease;z-index:5}.ai-chat-widget.dark .ai-chat-input-wrapper{background:#27272a;border-color:#3f3f46}.ai-chat-input-wrapper:focus-within{border-color:var(--primary-color);box-shadow:0 0 0 2px rgba(var(--primary-color-rgb,0,119,255),.15)}.ai-chat-input{background:transparent;border:none;color:var(--text-color);flex:1;font-family:inherit;font-size:14px;line-height:1.4;max-height:100px;min-height:20px;outline:none;padding:8px 0;resize:none}.ai-chat-input::placeholder{color:rgba(0,0,0,.35)}.ai-chat-widget.dark .ai-chat-input::placeholder{color:hsla(0,0%,100%,.35)}.ai-chat-send-button{align-items:center;background:transparent;border:none;border-radius:8px;color:#a1a1aa;cursor:pointer;display:flex;flex-shrink:0;height:36px;justify-content:center;padding:0;transition:all .15s ease;width:36px}.ai-chat-widget.dark .ai-chat-send-button{color:#71717a}.ai-chat-send-button.active{background:var(--primary-color,#07f);color:#fff}.ai-chat-send-button.active:hover:not(:disabled){opacity:.9}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-tool-message{align-items:center;animation:toolPulse 2s ease-in-out infinite;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);background:linear-gradient(135deg,rgba(16,185,129,.15),rgba(16,185,129,.08));border:1px solid rgba(16,185,129,.2);border-radius:16px;display:inline-flex;gap:10px;padding:10px 16px}@keyframes toolPulse{0%,to{box-shadow:0 0 0 0 rgba(16,185,129,.2)}50%{box-shadow:0 0 0 8px rgba(16,185,129,0)}}.tool-finished{align-items:center;animation:toolComplete .5s var(--spring-bounce);background:linear-gradient(135deg,#10b981,#059669);border-radius:50%;color:#fff;display:inline-flex;height:28px;justify-content:center;position:relative;width:28px}@keyframes toolComplete{0%{transform:scale(0) rotate(-180deg)}to{transform:scale(1) rotate(0deg)}}.tool-indicator{align-items:center;background:linear-gradient(135deg,rgba(59,130,246,.2),rgba(59,130,246,.1));border-radius:50%;color:#3b82f6;display:inline-flex;height:24px;justify-content:center;position:relative;width:24px}.tool-indicator.started:after{animation:toolSpin .8s linear infinite;border:2px solid transparent;border-radius:50%;border-top-color:#3b82f6;content:\"\";inset:-2px;position:absolute}@keyframes toolSpin{to{transform:rotate(1turn)}}.ai-chat-welcome{align-items:center;animation:welcomeFadeIn var(--duration-slow) var(--spring-smooth);display:flex;flex-direction:column;justify-content:center;min-height:200px;padding:60px 32px 40px;text-align:center}@keyframes welcomeFadeIn{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}.ai-chat-welcome-title{color:var(--primary-color);font-size:28px;font-weight:700;letter-spacing:-.03em;margin-bottom:12px}.ai-chat-welcome-text{color:var(--text-color);font-size:16px;line-height:1.6;max-width:280px;opacity:.6}.ai-chat-suggested-questions{bottom:76px;left:0;padding:0 16px 12px;position:absolute;right:0;z-index:5}.ai-chat-suggested-questions-list{display:flex;flex-direction:column;gap:6px}.ai-chat-suggested-question{align-items:center;background:#fff;border:1px solid #e5e7eb;border-radius:10px;color:#374151;cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:10px;justify-content:space-between;padding:10px 14px;text-align:left;transition:all .15s ease;width:100%}.ai-chat-widget.dark .ai-chat-suggested-question{background:#18181b;border-color:#27272a;color:#e4e4e7}.ai-chat-suggested-question:hover{background:#f4f4f5;border-color:#d4d4d8}.ai-chat-widget.dark .ai-chat-suggested-question:hover{background:#27272a;border-color:#3f3f46}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question-text{flex:1;line-height:1.4}.ai-chat-suggested-question-icon{color:var(--primary-color,#07f);flex-shrink:0;opacity:.7;transition:transform .15s ease,opacity .15s ease}.ai-chat-suggested-question:hover .ai-chat-suggested-question-icon{opacity:1;transform:translateX(3px)}.ai-chat-feedback-button{align-items:center;background:rgba(0,0,0,.04);border:none;border-radius:8px;cursor:pointer;display:flex;font-size:16px;gap:4px;padding:6px 10px;transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:rgba(0,0,0,.08);transform:scale(1.15)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button.active{background:rgba(var(--primary-color-rgb,0,119,255),.15)}@media (max-width:480px){.ai-chat-window{animation:mobileSlideUp var(--duration-normal) var(--spring-smooth);border-radius:0!important;bottom:0!important;height:100%!important;left:0!important;position:fixed!important;right:0!important;top:0!important;width:100%!important}@keyframes mobileSlideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}.ai-chat-header{padding-top:max(16px,env(safe-area-inset-top))}.ai-chat-input-container{padding-bottom:max(20px,env(safe-area-inset-bottom))}}";
22394
+ var css_248z = ".ai-chat-widget{--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:18px;--radius-pill:9999px;--radius-window-top:22px;--radius-window-bottom:44px;--radius-window-gutter:16px;--radius-chat-bubble:14px;--radius-preset-badge:13px;--radius-history-item:14px;--radius-action-badge:14px;--radius-input:62px;--space-xs:4px;--space-sm:8px;--space-md:16px;--space-lg:24px;--space-xl:32px;--text-xs:12px;--text-sm:14px;--text-md:15px;--text-lg:18px;--text-xl:22px;--text-2xl:28px;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--line-height-tight:1.3;--line-height-normal:1.4;--line-height-relaxed:1.6;--bg-primary:#fff;--bg-secondary:#f4f4f4;--bg-tertiary:#e5e7eb;--bg-hover:#e5e7eb;--text-primary:#3e3e3e;--text-secondary:#000;--text-muted:#71717a;--text-placeholder:#a1a1aa;--border-default:#d3d3d3;--border-subtle:#e5e7eb;--border-muted:#f4f4f5;--user-bg:#f4f3f0;--user-text:#000;--user-bg-hover:#e8e7e4;--agent-bg:transparent;--agent-text:#000;--input-bg:#f4f4f4;--input-border:#d3d3d3;--input-text:#000;--btn-primary-bg:#151515;--btn-primary-text:#f4f4f4;--btn-secondary-bg:transparent;--btn-secondary-text:#71717a;--spring-bounce:cubic-bezier(0.34,1.56,0.64,1);--spring-smooth:cubic-bezier(0.4,0,0.2,1);--spring-snappy:cubic-bezier(0.2,0,0,1);--duration-fast:0.15s;--duration-normal:0.25s;--duration-slow:0.35s;--shadow-sm:0 1px 2px rgba(0,0,0,.05);--shadow-md:0 2px 8px rgba(0,0,0,.1);--shadow-lg:0 4px 16px rgba(0,0,0,.12);--shadow-window:0px 0px 15px 9px rgba(0,0,0,.1);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03)}.ai-chat-widget.dark{--bg-primary:#282625;--bg-secondary:#4a4846;--bg-tertiary:#484848;--bg-hover:#484848;--text-primary:#fff;--text-secondary:#fff;--text-muted:#a1a1aa;--text-placeholder:#71717a;--border-default:#5d5b5b;--border-subtle:#5d5b5b;--border-muted:#5d5b5b;--user-bg:#484848;--user-text:#fff;--user-bg-hover:#5a5a5a;--agent-bg:transparent;--agent-text:#fff;--input-bg:#4a4846;--input-border:#5d5b5b;--input-text:#fff;--btn-primary-bg:#fff;--btn-primary-text:#312f2d;--btn-secondary-bg:transparent;--btn-secondary-text:#a1a1aa;--shadow-window:0px 0px 15px 9px rgba(0,0,0,.2);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03);--shadow-input:0px 0px 10px rgba(0,0,0,.15)}.ai-chat-widget{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget-container{font-size:var(--text-sm);line-height:1.5;position:fixed;z-index:9999}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}@keyframes windowOpen{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes windowClose{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes messageSlideIn{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes welcomeFadeIn{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes typingPulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-4px) scale(1.1)}}@keyframes ai-chat-gear-spin{to{transform:rotate(1turn)}}@keyframes ai-chat-tool-active{0%,to{background:var(--bg-secondary);opacity:1}50%{background:var(--bg-tertiary);opacity:1}}@keyframes feedbackMorph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes checkmarkPop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes ai-chat-history-exit{to{opacity:0;transform:translateY(-18px)}}@media (max-width:480px){.ai-chat-window{animation:mobileSlideUp var(--duration-normal) var(--spring-smooth);border-radius:0!important;bottom:0!important;height:100%!important;left:0!important;position:fixed!important;right:0!important;top:0!important;width:100%!important}@keyframes mobileSlideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}.ai-chat-header{padding-top:max(16px,env(safe-area-inset-top))}.ai-chat-input-container{padding-bottom:max(20px,env(safe-area-inset-bottom))}}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--button-border-color,var(--button-color,var(--btn-primary-bg)));border-radius:50%;box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));cursor:pointer;display:flex;height:var(--button-size,56px);justify-content:center;overflow:hidden;position:relative;transition:filter var(--duration-fast) ease,transform var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{transform:scale(1.02)}.ai-chat-button:active{transform:scale(.98)}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-window{animation:windowOpen var(--duration-slow,.35s) var(--spring-bounce,cubic-bezier(.34,1.56,.64,1));background:var(--bg-primary,#fff);border:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px);box-shadow:var(--shadow-window,0 0 15px 5px rgba(0,0,0,.08));display:flex;flex-direction:column;overflow:hidden;position:absolute;transform-origin:bottom right;z-index:2}.ai-chat-widget.dark .ai-chat-window{background:var(--bg-primary,#282625);border-color:var(--border-default,#5d5b5b);border-width:.7px}.ai-chat-window.closing{animation:windowClose var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:580px;width:380px}.ai-chat-window.size-medium{height:720px;width:440px}.ai-chat-window.size-large{height:820px;width:520px}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-header{align-items:center;background:var(--bg-primary,#fff);border-bottom:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) 0 0;display:flex;justify-content:space-between;padding:18px var(--space-md,16px);position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:var(--bg-primary,#282625);border-bottom-color:var(--border-default,#5d5b5b);border-bottom-width:.7px}.ai-chat-header.is-history{padding-left:var(--space-md)}.ai-chat-header.is-history .ai-chat-title{flex:1;min-width:0;overflow:hidden;padding-right:var(--space-lg);text-overflow:ellipsis;white-space:nowrap}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:var(--space-lg)}.ai-chat-header-actions{align-items:center;display:flex;gap:var(--space-sm)}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-xl,22px);font-weight:var(--font-weight-bold,700);letter-spacing:-.02em}.ai-chat-widget.dark .ai-chat-title{color:var(--text-primary,#fff)}.ai-chat-close-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-primary);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover{color:var(--text-muted)}.ai-chat-close-button:active{transform:scale(.95)}.ai-chat-header-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all var(--duration-fast) ease;width:32px}.ai-chat-header-button:hover{background:var(--bg-secondary);color:var(--text-secondary)}.ai-chat-header-button svg{height:18px;width:18px}.ai-chat-messages{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;align-items:stretch;background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;gap:var(--space-md,16px);justify-content:flex-start;overflow-x:hidden;overflow-y:auto;padding:var(--space-lg,24px) var(--space-md,16px) 100px;position:relative;scroll-behavior:smooth;scrollbar-width:none}.ai-chat-widget.dark .ai-chat-messages{background:var(--bg-primary,#18181b)}.ai-chat-messages::-webkit-scrollbar{display:none}.ai-chat-message{animation:messageSlideIn var(--duration-normal) var(--spring-bounce);display:flex;flex-direction:column;gap:6px}.ai-chat-message-content{word-wrap:break-word;font-size:var(--text-md);line-height:var(--line-height-relaxed);max-width:85%}.ai-chat-message.user{align-items:flex-end}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border:none;border-radius:var(--radius-chat-bubble,15px);box-shadow:none;color:var(--user-text,#000);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#484848);color:var(--user-text,#fff)}.ai-chat-message.user .ai-chat-message-meta{justify-content:flex-end;padding-right:var(--space-xs)}.ai-chat-message.assistant{align-items:flex-start}.ai-chat-message.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);border:none;color:var(--agent-text,#18181b);padding:0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fafafa)}.ai-chat-message.system{align-items:center}.ai-chat-message.system .ai-chat-message-content{background:hsla(48,96%,89%,.8);border-radius:var(--radius-md);color:#92400e;font-size:var(--text-xs);font-style:italic;max-width:90%;padding:var(--space-sm) var(--space-md);text-align:center}.ai-chat-widget.dark .ai-chat-message.system .ai-chat-message-content{background:rgba(120,53,15,.5);color:#fef3c7}.ai-chat-message.tool{align-items:flex-start}.ai-chat-message.tool .ai-chat-message-content{background:rgba(219,234,254,.8);border-radius:var(--radius-chat-bubble);border-bottom-left-radius:var(--radius-xs);color:#1e40af;font-family:Courier New,monospace;font-size:var(--text-sm);padding:var(--space-sm) var(--space-md)}.ai-chat-widget.dark .ai-chat-message.tool .ai-chat-message-content{background:rgba(30,58,138,.5);color:#dbeafe}.ai-chat-message-meta{align-items:center;color:var(--text-muted);display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding-left:var(--space-xs)}.ai-chat-message-timestamp{font-size:var(--text-xs);line-height:1}.ai-chat-typing{align-items:center;animation:messageSlideIn var(--duration-normal) var(--spring-bounce);background:transparent;display:flex;gap:5px;padding:0}.ai-chat-typing-dot{animation:typingPulse 1.4s ease-in-out infinite;background:var(--text-muted);border-radius:50%;height:6px;width:6px}.ai-chat-typing-dot:nth-child(2){animation-delay:.15s}.ai-chat-typing-dot:nth-child(3){animation-delay:.3s}.ai-chat-welcome{align-items:stretch;animation:welcomeFadeIn var(--duration-slow) var(--spring-smooth);display:flex;flex-direction:column;justify-content:flex-start;padding:0;text-align:left}.ai-chat-welcome-text,.ai-chat-welcome-title{align-self:flex-start}.ai-chat-welcome-title{color:var(--text-primary);font-size:var(--text-2xl);font-weight:var(--font-weight-semibold);letter-spacing:-.02em;margin-bottom:var(--space-md)}.ai-chat-welcome-text{color:var(--text-secondary);font-size:var(--text-md);line-height:var(--line-height-relaxed);max-width:100%}.ai-chat-error{align-items:flex-start;align-self:center;background:var(--bg-secondary);border:none;border-radius:var(--radius-chat-bubble);color:var(--text-primary);display:flex;font-size:var(--text-md);font-weight:var(--font-weight-normal);gap:10px;line-height:1.5;margin:0 auto;max-width:90%;padding:10px var(--space-md)}.ai-chat-error:before{align-items:center;background:rgba(239,68,68,.15);border-radius:50%;color:#ef4444;content:\"⚠\";display:flex;flex-shrink:0;font-size:var(--text-xs);font-weight:700;height:18px;justify-content:center;margin-top:2px;width:18px}.ai-chat-widget.dark .ai-chat-error:before{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 12px}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content ol,.ai-chat-message.assistant .ai-chat-message-content ul{margin:8px 0 12px;padding-left:24px}.ai-chat-message.assistant .ai-chat-message-content li{line-height:1.5;margin:6px 0}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content em{font-style:italic}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.06);border-radius:var(--radius-sm);font-family:SF Mono,Consolas,Monaco,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.06);border-radius:var(--radius-md);margin:8px 0 12px;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.08)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;border-radius:0;padding:0}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--btn-primary-bg);color:var(--text-muted);margin:8px 0 12px;padding:4px 0 4px 12px}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content a:hover{opacity:.8}.ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-message.assistant .ai-chat-message-content h2,.ai-chat-message.assistant .ai-chat-message-content h3,.ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-message.assistant .ai-chat-message-content h6{font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);margin:16px 0 8px}.ai-chat-message.assistant .ai-chat-message-content h1:first-child,.ai-chat-message.assistant .ai-chat-message-content h2:first-child,.ai-chat-message.assistant .ai-chat-message-content h3:first-child{margin-top:0}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle);margin:12px 0}.ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#fff) 50%,var(--bg-primary,#fff) 100%);bottom:0;left:0;padding-top:30px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#282625) 50%,var(--bg-primary,#282625) 100%)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px);padding-top:30px}.ai-chat-input-wrapper{align-items:center;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);display:flex;gap:0;height:52px;padding:6px 6px 6px 12px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-widget.dark .ai-chat-input-wrapper{background:var(--input-bg,#4a4846);border-color:var(--input-border,#5d5b5b);border-width:.7px;box-shadow:var(--shadow-input,0 0 10px rgba(0,0,0,.15))}.ai-chat-input-wrapper:focus-within{border-color:var(--text-muted,#a1a1aa)}.ai-chat-input{background:transparent;border:none;color:var(--input-text,#000);flex:1;font-family:inherit;font-size:var(--text-md,15px);height:20px;line-height:var(--line-height-normal,1.4);max-height:20px;min-height:20px;outline:none;overflow:hidden;padding:0 var(--space-sm,8px);resize:none}.ai-chat-widget.dark .ai-chat-input{color:var(--input-text,#fff)}.ai-chat-input::placeholder{color:var(--text-placeholder,#a1a1aa)}.ai-chat-widget.dark .ai-chat-input::placeholder{color:var(--text-placeholder,#52525b)}.ai-chat-file-button{align-items:center;background:transparent;border:none;color:var(--text-placeholder);cursor:pointer;display:flex;flex-shrink:0;height:28px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:28px}.ai-chat-file-button:hover{color:var(--text-secondary)}.ai-chat-file-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-send-button{align-items:center;background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));border:none;border-radius:50%;color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4));cursor:pointer;display:flex;flex-shrink:0;height:40px;justify-content:center;padding:0;transition:all var(--duration-fast,.15s) ease;width:40px}.ai-chat-widget.dark .ai-chat-send-button{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4))}.ai-chat-widget.dark .ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button:hover:not(:disabled){opacity:.8}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.3}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-sm)}.ai-chat-file-item{align-items:center;background:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding:6px 10px}.ai-chat-file-extension{background:var(--btn-primary-bg);border-radius:3px;color:var(--btn-primary-text);display:inline-block;font-size:10px;font-weight:var(--font-weight-semibold);min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:var(--font-weight-medium);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:var(--space-xs);transition:opacity var(--duration-fast) ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-suggested-questions{align-self:flex-end;margin:0;padding:16px 0 0;width:100%}.ai-chat-suggested-questions-list{align-items:center;display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.ai-chat-suggested-question{background:var(--primary-color,var(--button-color,var(--user-bg,#f4f3f0)));border:none;border-radius:var(--radius-preset-badge,13px);color:var(--button-icon-color,var(--user-text,#000));cursor:pointer;font-size:14px;font-weight:400;line-height:1.3;padding:8px 14px;transition:background .15s ease,opacity .15s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:var(--primary-color,var(--button-color,var(--user-bg,#484848)));color:var(--button-icon-color,var(--user-text,#fff))}.ai-chat-suggested-question-text{white-space:nowrap}.ai-chat-suggested-question:hover{filter:brightness(.9)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{filter:brightness(1.15)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question-icon{display:none}.ai-chat-feedback-buttons{align-items:center;display:flex;gap:var(--space-xs)}.ai-chat-feedback{align-items:center;display:inline-flex;gap:0;height:20px}.ai-chat-feedback-button{align-items:center;background:transparent!important;border:none;border-radius:var(--radius-sm);color:var(--text-placeholder);cursor:pointer;display:flex;font-size:var(--text-sm);height:20px;justify-content:center;padding:var(--space-xs);transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:var(--text-secondary)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--text-primary)}.ai-chat-feedback-submitted{align-items:center;animation:feedbackMorph .3s var(--spring-bounce);display:flex;gap:6px}.ai-chat-feedback-checkmark{animation:checkmarkPop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-sm);font-weight:var(--font-weight-medium)}.ai-chat-history-panel{background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-history-panel{background:var(--bg-primary,#18181b)}.ai-chat-history-empty,.ai-chat-history-loading{align-items:center;color:var(--text-muted);display:flex;flex:1;font-size:var(--text-sm);justify-content:center;padding:var(--space-lg);text-align:center}.ai-chat-history-list{-ms-overflow-style:none;display:flex;flex:1;flex-direction:column;gap:var(--space-sm);overflow-y:auto;padding:var(--space-md) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items:stretch;background:var(--user-bg,#f4f4f5);border:none;border-radius:var(--radius-history-item,15px);cursor:pointer;display:flex;flex-direction:column;margin:0;padding:var(--space-sm,8px) var(--space-md,16px);text-align:left;transition:background var(--duration-fast,.15s) ease;width:100%}.ai-chat-widget.dark .ai-chat-history-item{background:var(--user-bg,#27272a)}.ai-chat-history-item:hover{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item:hover{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item.active{background:var(--user-bg-hover,#e5e7eb)}.ai-chat-widget.dark .ai-chat-history-item.active{background:var(--user-bg-hover,#3f3f46)}.ai-chat-history-item-preview{color:var(--text-primary,#18181b);font-size:var(--text-sm,14px);font-weight:var(--font-weight-medium,500);line-height:var(--line-height-normal,1.4);margin-bottom:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-widget.dark .ai-chat-history-item-preview{color:var(--text-primary,#fafafa)}.ai-chat-history-item.active .ai-chat-history-item-preview{font-weight:var(--font-weight-medium)}.ai-chat-history-item-meta{display:none}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:var(--space-sm) 0 6px}.ai-chat-tool-gear{align-items:center;color:var(--text-primary);display:inline-flex;height:26px;justify-content:center;width:26px}.ai-chat-tool-gear.spinning{animation:ai-chat-gear-spin .9s linear infinite}.ai-chat-tool-pills{display:flex;flex-wrap:wrap;gap:var(--space-sm)}.ai-chat-tool-pill{align-items:center;border-radius:var(--radius-pill);color:var(--button-icon-color,var(--btn-primary-text,var(--text-primary)));display:inline-flex;font-size:var(--text-sm);font-weight:var(--font-weight-medium);justify-content:center;line-height:1;padding:var(--space-sm) 14px}.ai-chat-tool-pill,.ai-chat-tool-pill.active{background:var(--primary-color,var(--button-color,var(--btn-primary-bg,var(--bg-secondary))))}.ai-chat-tool-pill.active{animation:ai-chat-tool-active 1.1s ease-in-out infinite;overflow:hidden;position:relative}.ai-chat-tool-pill.done{background:var(--primary-color,var(--button-color,var(--btn-primary-bg)));color:var(--button-icon-color,var(--btn-primary-text))}.ai-chat-tool-indicators{display:flex;gap:6px;margin-top:6px}.tool-indicator{align-items:center;background:linear-gradient(135deg,rgba(59,130,246,.2),rgba(59,130,246,.1));border-radius:50%;color:#3b82f6;display:inline-flex;height:24px;justify-content:center;position:relative;width:24px}.tool-indicator .icon{font-size:var(--text-xs);line-height:1;z-index:1}.tool-indicator.started:after{animation:ai-chat-gear-spin .8s linear infinite;border:2px solid transparent;border-radius:50%;border-top-color:#3b82f6;content:\"\";inset:-2px;position:absolute}.ai-chat-tool-message{align-items:center;background:hsla(0,0%,50%,.1);border:none;border-radius:var(--radius-pill);color:hsla(0,0%,50%,.8);display:inline-flex;font-size:12px;gap:5px;padding:4px 10px}.ai-chat-tool-message .ai-chat-tool-spinner{animation:ai-chat-tool-spin 1s linear infinite;flex-shrink:0;opacity:.6}.ai-chat-tool-message .ai-chat-tool-check{flex-shrink:0;opacity:.7}.ai-chat-tool-message .ai-chat-tool-error{color:#ef4444;flex-shrink:0;opacity:.7}.ai-chat-tool-message.error{background:rgba(239,68,68,.1);color:rgba(239,68,68,.9)}.tool-name{font-size:12px;font-weight:var(--font-weight-regular);line-height:1.2;white-space:nowrap}@keyframes ai-chat-tool-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes ai-chat-tool-check-appear{0%{opacity:0;transform:scale(.5)}to{opacity:.7;transform:scale(1)}}.ai-chat-sources{background:rgba(0,0,0,.02);border-radius:6px;font-size:var(--text-xs);margin-top:var(--space-sm);overflow:hidden}.ai-chat-sources-toggle{align-items:center;background:none;border:none;cursor:pointer;display:flex;gap:6px;padding:var(--space-sm) 10px;text-align:left;transition:background var(--duration-fast) ease;width:100%}.ai-chat-sources-toggle:hover{background:rgba(0,0,0,.03)}.ai-chat-sources-icon{color:var(--text-muted);font-size:10px;transition:transform var(--duration-fast) ease}.ai-chat-sources-title{color:var(--text-primary);flex:1;font-size:11px;font-weight:var(--font-weight-semibold);letter-spacing:.5px;text-transform:uppercase}.ai-chat-source-item{border-top:1px solid rgba(0,0,0,.05);color:var(--text-muted);display:flex;gap:var(--space-sm);padding:var(--space-sm) 10px}.ai-chat-source-item:last-child{border-bottom:none}.ai-chat-source-number{color:var(--btn-primary-bg);flex-shrink:0;font-weight:var(--font-weight-semibold)}.ai-chat-source-details{display:flex;flex:1;flex-direction:column;gap:var(--space-xs)}.ai-chat-source-score{color:var(--text-placeholder);font-size:11px}.ai-chat-source-content{color:var(--text-muted);font-size:11px;font-style:italic;line-height:var(--line-height-normal)}.ai-chat-source-metadata{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}.ai-chat-source-meta-item{background:rgba(0,0,0,.05);border-radius:3px;color:var(--text-muted);font-size:10px;padding:2px 6px}";
22041
22395
  styleInject(css_248z);
22042
22396
 
22043
22397
  // Icon components mapping
@@ -22045,17 +22399,76 @@ const iconComponents = {
22045
22399
  FiMessageCircle: () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" }) })),
22046
22400
  FiChevronDown: () => (jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) })),
22047
22401
  };
22048
- const ChatWidget = ({ widgetId, apiUrl = window.location.origin, position = 'bottom-right', primaryColor, onOpen, onClose, onMessage, onError, }) => {
22402
+ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, theme, suggestedQuestions, customStyles, onOpen, onClose, onMessage, onError, }) => {
22049
22403
  const [isOpen, setIsOpen] = react.useState(false);
22050
22404
  const [autoDetectedTheme, setAutoDetectedTheme] = react.useState('light');
22051
22405
  const widgetRef = react.useRef(null);
22052
22406
  const containerRef = react.useRef(null);
22053
- const { messages, isLoading, isTyping, error, config, sendMessage, submitFeedback, } = useChat({
22054
- widgetId,
22407
+ // Default config for preview mode
22408
+ const defaultPreviewConfig = {
22409
+ appearance: {
22410
+ primaryColor: primaryColor || '#0077FF',
22411
+ position: position || 'bottom-right',
22412
+ size: size || 'small',
22413
+ headerTitle: headerTitle || 'AI Assistant',
22414
+ welcomeTitle: welcomeTitle || 'Welcome!',
22415
+ welcomeMessage: welcomeMessage || 'Hi there! How can I help you today?',
22416
+ placeholder: placeholder || 'Ask me anything...',
22417
+ },
22418
+ settings: {
22419
+ autoOpen: false,
22420
+ persistConversation: true,
22421
+ showChatHistory: true,
22422
+ showTimestamps: true,
22423
+ showTypingIndicator: true,
22424
+ enableFileUpload: false,
22425
+ enableFeedback: true,
22426
+ showSources: false,
22427
+ sourceDisplayMode: 'none',
22428
+ },
22429
+ behavior: {
22430
+ agentic: false,
22431
+ },
22432
+ knowledgeBases: [],
22433
+ };
22434
+ // Merge preview config with defaults
22435
+ const mergedPreviewConfig = {
22436
+ ...defaultPreviewConfig,
22437
+ ...previewConfig,
22438
+ appearance: {
22439
+ ...defaultPreviewConfig.appearance,
22440
+ ...previewConfig?.appearance,
22441
+ },
22442
+ settings: {
22443
+ ...defaultPreviewConfig.settings,
22444
+ ...previewConfig?.settings,
22445
+ },
22446
+ behavior: {
22447
+ ...defaultPreviewConfig.behavior,
22448
+ ...previewConfig?.behavior,
22449
+ },
22450
+ };
22451
+ // Always call useChat hook (React rules), but use a dummy widgetId in preview mode
22452
+ // The hook will fail to load config, but we don't use its results in preview mode anyway
22453
+ const chatHook = useChat({
22454
+ widgetId: previewMode ? '__preview__' : (widgetId || '__preview__'),
22055
22455
  apiUrl,
22056
- onMessage,
22057
- onError,
22456
+ onMessage: previewMode ? undefined : onMessage,
22457
+ onError: previewMode ? undefined : onError,
22058
22458
  });
22459
+ // Extract values from hook or use preview defaults
22460
+ const messages = previewMode ? [] : chatHook.messages;
22461
+ const isLoading = previewMode ? false : chatHook.isLoading;
22462
+ const isTyping = previewMode ? false : chatHook.isTyping;
22463
+ const error = previewMode ? null : chatHook.error;
22464
+ const config = previewMode ? mergedPreviewConfig : chatHook.config;
22465
+ const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
22466
+ const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
22467
+ const conversations = previewMode ? [] : chatHook.conversations;
22468
+ const loadConversations = previewMode ? (() => { }) : chatHook.loadConversations;
22469
+ const switchConversation = previewMode ? (() => Promise.resolve()) : chatHook.switchConversation;
22470
+ const startNewConversation = previewMode ? (() => { }) : chatHook.startNewConversation;
22471
+ const conversationId = previewMode ? '' : chatHook.conversationId;
22059
22472
  // Auto-detect theme from background
22060
22473
  react.useEffect(() => {
22061
22474
  if (!containerRef.current)
@@ -22093,8 +22506,8 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, position = 'bot
22093
22506
  }, [config, autoDetectedTheme]);
22094
22507
  // Handle auto-open
22095
22508
  react.useEffect(() => {
22096
- if (config?.behavior.autoOpen) {
22097
- const delay = config.behavior.autoOpenDelay || 0;
22509
+ if (config?.settings.autoOpen) {
22510
+ const delay = config.settings.autoOpenDelay || 0;
22098
22511
  const timer = setTimeout(() => {
22099
22512
  setIsOpen(true);
22100
22513
  onOpen?.();
@@ -22103,26 +22516,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, position = 'bot
22103
22516
  }
22104
22517
  return undefined;
22105
22518
  }, [config, onOpen]);
22106
- // Handle close on outside click - always enabled for better UX
22107
- react.useEffect(() => {
22108
- if (!isOpen)
22109
- return;
22110
- const handleClickOutside = (event) => {
22111
- // Check if click is outside the widget container
22112
- if (widgetRef.current && !widgetRef.current.contains(event.target)) {
22113
- setIsOpen(false);
22114
- onClose?.();
22115
- }
22116
- };
22117
- // Small delay to prevent immediate close on open
22118
- const timer = setTimeout(() => {
22119
- document.addEventListener('mousedown', handleClickOutside);
22120
- }, 150);
22121
- return () => {
22122
- clearTimeout(timer);
22123
- document.removeEventListener('mousedown', handleClickOutside);
22124
- };
22125
- }, [isOpen, onClose]);
22126
22519
  // Handle close on Escape key
22127
22520
  react.useEffect(() => {
22128
22521
  if (!isOpen)
@@ -22136,31 +22529,33 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, position = 'bot
22136
22529
  document.addEventListener('keydown', handleEscapeKey);
22137
22530
  return () => document.removeEventListener('keydown', handleEscapeKey);
22138
22531
  }, [isOpen, onClose]);
22139
- // Determine theme - always auto-detect from background
22532
+ // Determine theme - use prop override if provided, otherwise auto-detect
22140
22533
  const appearanceConfig = config?.appearance;
22141
- const effectiveTheme = autoDetectedTheme;
22142
- // Determine position (config takes priority over prop)
22143
- const effectivePosition = config?.appearance.position || position;
22144
- // Get accent color from config or prop
22145
- const accentColor = primaryColor || appearanceConfig?.primaryColor || '#0077FF';
22534
+ const effectiveTheme = theme ?? autoDetectedTheme;
22535
+ // Determine position (prop override takes priority for live preview)
22536
+ const effectivePosition = position || config?.appearance.position || 'bottom-right';
22537
+ // Get accent color from prop or config (empty string means no accent color / vanilla mode)
22538
+ const accentColor = primaryColor ?? appearanceConfig?.primaryColor ?? '';
22539
+ // Apply prop overrides for live preview (props take priority over config)
22540
+ size || appearanceConfig?.size || 'small';
22541
+ const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? '';
22542
+ const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
22543
+ const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
22544
+ const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
22146
22545
  // Generate styles using simplified theme system
22147
22546
  const simpleAppearance = {
22148
- accentColor,
22149
- size: appearanceConfig?.size || 'small',
22150
- welcomeMessage: appearanceConfig?.welcomeMessage || '',
22151
- placeholder: appearanceConfig?.placeholder || '',
22152
- headerTitle: appearanceConfig?.headerTitle || '',
22153
- };
22547
+ accentColor};
22154
22548
  // Generate theme styles from accent color
22155
22549
  const generatedStyles = generateThemeStyles(simpleAppearance, effectiveTheme);
22156
22550
  // Also apply legacy styles for backward compatibility
22157
22551
  const legacyStyles = appearanceConfig
22158
22552
  ? applyAppearanceStyles(appearanceConfig)
22159
22553
  : {};
22160
- // Merge styles (generated takes priority for new simplified system)
22161
- const customStyles = {
22554
+ // Merge styles (generated takes priority for new simplified system, then custom overrides)
22555
+ const mergedStyles = {
22162
22556
  ...legacyStyles,
22163
22557
  ...generatedStyles,
22558
+ ...customStyles,
22164
22559
  };
22165
22560
  // Debug logging for theme and styles
22166
22561
  react.useEffect(() => {
@@ -22185,14 +22580,19 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, position = 'bot
22185
22580
  await submitFeedback(messageId, feedback);
22186
22581
  };
22187
22582
  // Don't render until config is loaded to avoid flash of unstyled content
22188
- if (!config) {
22583
+ // In preview mode, config is always available
22584
+ if (!config && !previewMode) {
22189
22585
  console.log('[ChatWidget] Not rendering - config not loaded yet');
22190
22586
  return null;
22191
22587
  }
22192
22588
  console.log('[ChatWidget] Rendering widget', { isOpen, hasConfig: !!config });
22193
22589
  // Get button icon based on state
22194
22590
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
22195
- return (jsxRuntime.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: customStyles, children: jsxRuntime.jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition}`, children: [isOpen && (jsxRuntime.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback })), jsxRuntime.jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsxRuntime.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntime.jsx(IconComponent, {}) }) })] }) }));
22591
+ return (jsxRuntime.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxRuntime.jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition}`, children: [isOpen && (jsxRuntime.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback,
22592
+ // Chat history props (only active when persistConversation is true)
22593
+ conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, currentConversationId: conversationId,
22594
+ // Override props for live preview
22595
+ headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsxRuntime.jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsxRuntime.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntime.jsx(IconComponent, {}) }) })] }) }));
22196
22596
  };
22197
22597
 
22198
22598
  exports.ApiError = ApiError;