@chatwidgetai/chat-widget 0.3.0 → 0.3.6
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/ai-chat-widget.umd.js +1903 -437
- package/dist/ai-chat-widget.umd.js.map +1 -1
- package/dist/api/client.d.ts +11 -2
- package/dist/api/client.d.ts.map +1 -1
- package/dist/components/ChatWidget.d.ts +2 -1
- package/dist/components/ChatWidget.d.ts.map +1 -1
- package/dist/components/ChatWindow.d.ts +1 -1
- package/dist/components/ChatWindow.d.ts.map +1 -1
- package/dist/components/DataPolicyView.d.ts +14 -0
- package/dist/components/DataPolicyView.d.ts.map +1 -0
- package/dist/hooks/useChat/action-handler.d.ts +6 -0
- package/dist/hooks/useChat/action-handler.d.ts.map +1 -0
- package/dist/hooks/useChat/action-lifecycle.d.ts +19 -0
- package/dist/hooks/useChat/action-lifecycle.d.ts.map +1 -0
- package/dist/hooks/useChat/error-utils.d.ts +7 -0
- package/dist/hooks/useChat/error-utils.d.ts.map +1 -0
- package/dist/hooks/{useChat.d.ts → useChat/index.d.ts} +4 -2
- package/dist/hooks/useChat/index.d.ts.map +1 -0
- package/dist/hooks/useChat/message-hydration.d.ts +4 -0
- package/dist/hooks/useChat/message-hydration.d.ts.map +1 -0
- package/dist/hooks/useChat/stream-handlers.d.ts +27 -0
- package/dist/hooks/useChat/stream-handlers.d.ts.map +1 -0
- package/dist/hooks/useChat/stream-state.d.ts +8 -0
- package/dist/hooks/useChat/stream-state.d.ts.map +1 -0
- package/dist/hooks/useChat/types.d.ts +26 -0
- package/dist/hooks/useChat/types.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1904 -438
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1904 -437
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +22 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/utils/sse-parser.d.ts.map +1 -1
- package/package.json +7 -3
- package/dist/hooks/useChat.d.ts.map +0 -1
|
@@ -16696,11 +16696,14 @@
|
|
|
16696
16696
|
const reader = response.body.getReader();
|
|
16697
16697
|
const decoder = new TextDecoder();
|
|
16698
16698
|
let buffer = "";
|
|
16699
|
+
let eventCount = 0;
|
|
16699
16700
|
try {
|
|
16700
16701
|
while (true) {
|
|
16701
16702
|
const { done, value } = await reader.read();
|
|
16702
|
-
if (done)
|
|
16703
|
+
if (done) {
|
|
16704
|
+
console.log(`[SSE Parser] Stream ended normally after ${eventCount} events`);
|
|
16703
16705
|
break;
|
|
16706
|
+
}
|
|
16704
16707
|
buffer += decoder.decode(value, { stream: true });
|
|
16705
16708
|
const chunks = buffer.split("\n\n");
|
|
16706
16709
|
buffer = chunks.pop() || "";
|
|
@@ -16712,6 +16715,7 @@
|
|
|
16712
16715
|
const data = JSON.parse(line.slice(6));
|
|
16713
16716
|
if (validator) {
|
|
16714
16717
|
if (validator(data)) {
|
|
16718
|
+
eventCount++;
|
|
16715
16719
|
yield data;
|
|
16716
16720
|
}
|
|
16717
16721
|
else {
|
|
@@ -16719,6 +16723,7 @@
|
|
|
16719
16723
|
}
|
|
16720
16724
|
}
|
|
16721
16725
|
else {
|
|
16726
|
+
eventCount++;
|
|
16722
16727
|
yield data;
|
|
16723
16728
|
}
|
|
16724
16729
|
}
|
|
@@ -16731,6 +16736,10 @@
|
|
|
16731
16736
|
}
|
|
16732
16737
|
}
|
|
16733
16738
|
}
|
|
16739
|
+
catch (error) {
|
|
16740
|
+
console.error(`[SSE Parser] Stream error after ${eventCount} events:`, error);
|
|
16741
|
+
throw error;
|
|
16742
|
+
}
|
|
16734
16743
|
finally {
|
|
16735
16744
|
reader.releaseLock();
|
|
16736
16745
|
}
|
|
@@ -16864,7 +16873,7 @@
|
|
|
16864
16873
|
const result = await response.json();
|
|
16865
16874
|
return result.file;
|
|
16866
16875
|
}
|
|
16867
|
-
async *sendAgentMessageStream(conversationId, message, fileIds) {
|
|
16876
|
+
async *sendAgentMessageStream(conversationId, message, fileIds, signal) {
|
|
16868
16877
|
const headers = {
|
|
16869
16878
|
'Content-Type': 'application/json',
|
|
16870
16879
|
};
|
|
@@ -16880,6 +16889,7 @@
|
|
|
16880
16889
|
fileIds,
|
|
16881
16890
|
timeZone: this.getTimeZone(),
|
|
16882
16891
|
}),
|
|
16892
|
+
signal,
|
|
16883
16893
|
});
|
|
16884
16894
|
if (!response.ok) {
|
|
16885
16895
|
throw await buildApiError(response, 'Failed to send agent message');
|
|
@@ -16888,7 +16898,7 @@
|
|
|
16888
16898
|
return typeof data === 'object' && data !== null && 'type' in data;
|
|
16889
16899
|
});
|
|
16890
16900
|
}
|
|
16891
|
-
async *continueAgentMessageStream(conversationId, toolCallId, state) {
|
|
16901
|
+
async *continueAgentMessageStream(conversationId, toolCallId, state, signal) {
|
|
16892
16902
|
const headers = {
|
|
16893
16903
|
'Content-Type': 'application/json',
|
|
16894
16904
|
};
|
|
@@ -16904,6 +16914,7 @@
|
|
|
16904
16914
|
state,
|
|
16905
16915
|
timeZone: this.getTimeZone(),
|
|
16906
16916
|
}),
|
|
16917
|
+
signal,
|
|
16907
16918
|
});
|
|
16908
16919
|
if (!response.ok) {
|
|
16909
16920
|
throw await buildApiError(response, 'Failed to continue agent');
|
|
@@ -16912,6 +16923,33 @@
|
|
|
16912
16923
|
return typeof data === 'object' && data !== null && 'type' in data;
|
|
16913
16924
|
});
|
|
16914
16925
|
}
|
|
16926
|
+
async *dismissAgentMessageStream(conversationId, toolCallId, signal) {
|
|
16927
|
+
const headers = {
|
|
16928
|
+
'Content-Type': 'application/json',
|
|
16929
|
+
};
|
|
16930
|
+
if (this.config.currentRoute) {
|
|
16931
|
+
headers['X-Current-Route'] = this.config.currentRoute;
|
|
16932
|
+
}
|
|
16933
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/dismiss`, {
|
|
16934
|
+
method: 'POST',
|
|
16935
|
+
headers,
|
|
16936
|
+
body: JSON.stringify({
|
|
16937
|
+
conversationId: conversationId,
|
|
16938
|
+
toolCallId,
|
|
16939
|
+
reason: "user",
|
|
16940
|
+
}),
|
|
16941
|
+
signal,
|
|
16942
|
+
});
|
|
16943
|
+
if (response.status === 204) {
|
|
16944
|
+
return;
|
|
16945
|
+
}
|
|
16946
|
+
if (!response.ok) {
|
|
16947
|
+
throw await buildApiError(response, 'Failed to dismiss action');
|
|
16948
|
+
}
|
|
16949
|
+
yield* parseSSEStream(response, (data) => {
|
|
16950
|
+
return typeof data === 'object' && data !== null && 'type' in data;
|
|
16951
|
+
});
|
|
16952
|
+
}
|
|
16915
16953
|
/**
|
|
16916
16954
|
* Submit feedback for a message
|
|
16917
16955
|
*/
|
|
@@ -16974,6 +17012,27 @@
|
|
|
16974
17012
|
return [];
|
|
16975
17013
|
}
|
|
16976
17014
|
}
|
|
17015
|
+
/**
|
|
17016
|
+
* Create a demo conversation with preset messages
|
|
17017
|
+
* Used when demo animation completes to persist the demo conversation to the database
|
|
17018
|
+
*/
|
|
17019
|
+
async createDemoConversation(userMessage, assistantMessage) {
|
|
17020
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/demo-conversation`, {
|
|
17021
|
+
method: 'POST',
|
|
17022
|
+
headers: {
|
|
17023
|
+
'Content-Type': 'application/json',
|
|
17024
|
+
},
|
|
17025
|
+
body: JSON.stringify({
|
|
17026
|
+
userMessage,
|
|
17027
|
+
assistantMessage,
|
|
17028
|
+
timeZone: this.getTimeZone(),
|
|
17029
|
+
}),
|
|
17030
|
+
});
|
|
17031
|
+
if (!response.ok) {
|
|
17032
|
+
throw await buildApiError(response, 'Failed to create demo conversation');
|
|
17033
|
+
}
|
|
17034
|
+
return response.json();
|
|
17035
|
+
}
|
|
16977
17036
|
/**
|
|
16978
17037
|
* Validate widget access
|
|
16979
17038
|
*/
|
|
@@ -43800,22 +43859,19 @@
|
|
|
43800
43859
|
const formatToolName = (name) => {
|
|
43801
43860
|
return name
|
|
43802
43861
|
.replace(/^(action_|tool_)/, '')
|
|
43862
|
+
.replace(/-/g, '_')
|
|
43803
43863
|
.split('_')
|
|
43804
43864
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
43805
43865
|
.join(' ');
|
|
43806
43866
|
};
|
|
43807
|
-
const GearIcon = ({ spinning = false }) => (jsxRuntimeExports.jsxs("svg", { className: `ai-chat-tool-gear ${spinning ? 'spinning' : ''}`, width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" }), jsxRuntimeExports.jsx("path", { d: "M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z" }), jsxRuntimeExports.jsx("path", { d: "M12 2v2" }), jsxRuntimeExports.jsx("path", { d: "M12 22v-2" }), jsxRuntimeExports.jsx("path", { d: "m17 20.66-1-1.73" }), jsxRuntimeExports.jsx("path", { d: "M11 10.27 7 3.34" }), jsxRuntimeExports.jsx("path", { d: "m20.66 17-1.73-1" }), jsxRuntimeExports.jsx("path", { d: "m3.34 7 1.73 1" }), jsxRuntimeExports.jsx("path", { d: "M14 12h8" }), jsxRuntimeExports.jsx("path", { d: "M2 12h2" }), jsxRuntimeExports.jsx("path", { d: "m20.66 7-1.73 1" }), jsxRuntimeExports.jsx("path", { d: "m3.34 17 1.73-1" }), jsxRuntimeExports.jsx("path", { d: "m17 3.34-1 1.73" }), jsxRuntimeExports.jsx("path", { d: "m11 13.73-4 6.93" })] }));
|
|
43808
|
-
const CheckIcon$2 = () => (jsxRuntimeExports.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: jsxRuntimeExports.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
43809
|
-
const ErrorIcon = () => (jsxRuntimeExports.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: jsxRuntimeExports.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }));
|
|
43810
43867
|
function ToolIndicator({ badges, className = '' }) {
|
|
43811
|
-
|
|
43812
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-tool-row ${className}`, children: [jsxRuntimeExports.jsx(GearIcon, { spinning: isAnyLoading }), jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsxRuntimeExports.jsxs("div", { className: `ai-chat-tool-badge ${badge.status}`, children: [badge.status !== 'loading' && (badge.status === 'error' ? jsxRuntimeExports.jsx(ErrorIcon, {}) : jsxRuntimeExports.jsx(CheckIcon$2, {})), jsxRuntimeExports.jsx("span", { className: "tool-name", children: formatToolName(badge.name) })] }, badge.id))) })] }));
|
|
43868
|
+
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsxRuntimeExports.jsx("div", { className: `ai-chat-tool-badge ${badge.status}`, children: jsxRuntimeExports.jsx("span", { className: "tool-name", children: formatToolName(badge.name) }) }, badge.id))) }) }));
|
|
43813
43869
|
}
|
|
43814
43870
|
|
|
43815
43871
|
// SVG Icon components
|
|
43816
43872
|
const ThumbsUpIcon = () => (jsxRuntimeExports.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("path", { d: "M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3" }) }));
|
|
43817
43873
|
const ThumbsDownIcon = () => (jsxRuntimeExports.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("path", { d: "M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17" }) }));
|
|
43818
|
-
const CheckIcon$
|
|
43874
|
+
const CheckIcon$2 = () => (jsxRuntimeExports.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
43819
43875
|
const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
|
|
43820
43876
|
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
43821
43877
|
const [submitted, setSubmitted] = reactExports.useState(false);
|
|
@@ -43836,10 +43892,10 @@
|
|
|
43836
43892
|
setIsSubmitting(false);
|
|
43837
43893
|
}
|
|
43838
43894
|
};
|
|
43839
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsxRuntimeExports.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsxRuntimeExports.jsx(ThumbsUpIcon, {}) }), jsxRuntimeExports.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'negative' ? 'active' : ''}`, onClick: () => handleFeedback('negative'), disabled: isDisabled, "aria-label": "Not helpful", title: "This was not helpful", children: jsxRuntimeExports.jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-feedback-checkmark", children: jsxRuntimeExports.jsx(CheckIcon$
|
|
43895
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsxRuntimeExports.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsxRuntimeExports.jsx(ThumbsUpIcon, {}) }), jsxRuntimeExports.jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'negative' ? 'active' : ''}`, onClick: () => handleFeedback('negative'), disabled: isDisabled, "aria-label": "Not helpful", title: "This was not helpful", children: jsxRuntimeExports.jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-feedback-checkmark", children: jsxRuntimeExports.jsx(CheckIcon$2, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
|
|
43840
43896
|
};
|
|
43841
43897
|
|
|
43842
|
-
const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback,
|
|
43898
|
+
const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
|
|
43843
43899
|
const formatTime = (timestamp) => {
|
|
43844
43900
|
const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
|
|
43845
43901
|
return date.toLocaleTimeString('en-US', {
|
|
@@ -43859,15 +43915,15 @@
|
|
|
43859
43915
|
return null;
|
|
43860
43916
|
}
|
|
43861
43917
|
// AI message rendering
|
|
43918
|
+
// Note: Actions are rendered by ToolMessageGroup for tool messages, not here
|
|
43862
43919
|
if (isAssistant) {
|
|
43863
43920
|
const aiContent = message.message.content || '';
|
|
43864
43921
|
const hasContent = aiContent.trim().length > 0;
|
|
43865
43922
|
if (!hasContent)
|
|
43866
43923
|
return null;
|
|
43867
|
-
|
|
43868
|
-
|
|
43869
|
-
|
|
43870
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-error-indicator", children: [jsxRuntimeExports.jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsxRuntimeExports.jsx("span", { className: "error-text", children: "Error" })] })), jsxRuntimeExports.jsx(Markdown, { remarkPlugins: [remarkGfm], children: aiContent })] }), actionRenderer && message.action && actionRenderer(message, accentColor), showTimestamp && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntimeExports.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
|
|
43924
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-message-content", children: jsxRuntimeExports.jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
|
|
43925
|
+
table: ({ children, ...props }) => (jsxRuntimeExports.jsx("div", { className: "table-wrapper", children: jsxRuntimeExports.jsx("div", { className: "table-scroll", children: jsxRuntimeExports.jsx("table", { ...props, children: children }) }) })),
|
|
43926
|
+
}, children: aiContent }) }), showTimestamp && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntimeExports.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
|
|
43871
43927
|
}
|
|
43872
43928
|
// System message rendering
|
|
43873
43929
|
if (isSystem) {
|
|
@@ -43881,35 +43937,86 @@
|
|
|
43881
43937
|
return null;
|
|
43882
43938
|
};
|
|
43883
43939
|
|
|
43884
|
-
|
|
43885
|
-
|
|
43940
|
+
// Centralized action state logic
|
|
43941
|
+
function isActionComplete(state) {
|
|
43942
|
+
if (!state)
|
|
43943
|
+
return false;
|
|
43944
|
+
const TERMINAL_STATUSES = [
|
|
43945
|
+
'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
|
|
43946
|
+
'displaying', 'clicked', 'contacted', 'submitted', 'sent'
|
|
43947
|
+
];
|
|
43948
|
+
const status = state.status;
|
|
43949
|
+
if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
|
|
43950
|
+
return true;
|
|
43951
|
+
}
|
|
43952
|
+
// For non-halting actions (query_contact_directory, etc.) with results/success
|
|
43953
|
+
if (!status && (state.success !== undefined || state.results !== undefined)) {
|
|
43954
|
+
return true;
|
|
43955
|
+
}
|
|
43956
|
+
return false;
|
|
43957
|
+
}
|
|
43958
|
+
function isActionLoading(message) {
|
|
43959
|
+
if (!message.action)
|
|
43960
|
+
return false;
|
|
43961
|
+
if (message.action.done)
|
|
43962
|
+
return false;
|
|
43963
|
+
if (message.isStreaming)
|
|
43964
|
+
return true;
|
|
43965
|
+
const state = message.action.state;
|
|
43966
|
+
return !isActionComplete(state);
|
|
43967
|
+
}
|
|
43968
|
+
const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant, onActionDismiss, }) => {
|
|
43969
|
+
const visibleMessages = messages.filter(message => !message.action?.hidden);
|
|
43970
|
+
const actionMessages = visibleMessages.filter(message => message.action);
|
|
43971
|
+
// Debug logging
|
|
43972
|
+
console.log('[DEBUG ToolMessageGroup] ========================================');
|
|
43973
|
+
console.log('[DEBUG ToolMessageGroup] Total messages:', messages.length);
|
|
43974
|
+
console.log('[DEBUG ToolMessageGroup] Messages with action:', actionMessages.length);
|
|
43975
|
+
console.log('[DEBUG ToolMessageGroup] hasGetActionRenderer:', !!getActionRenderer);
|
|
43976
|
+
messages.forEach((msg, i) => {
|
|
43977
|
+
console.log(`[DEBUG ToolMessageGroup] Message ${i}:`, {
|
|
43978
|
+
id: msg.id,
|
|
43979
|
+
role: msg.message.role,
|
|
43980
|
+
hasAction: !!msg.action,
|
|
43981
|
+
actionImpl: msg.action?.implementation,
|
|
43982
|
+
toolExecuting: msg.toolExecuting,
|
|
43983
|
+
});
|
|
43984
|
+
});
|
|
43985
|
+
actionMessages.forEach((msg, i) => {
|
|
43986
|
+
const impl = msg.action?.implementation || '';
|
|
43987
|
+
const renderer = getActionRenderer?.(impl);
|
|
43988
|
+
console.log(`[DEBUG ToolMessageGroup] Action ${i}:`, {
|
|
43989
|
+
implementation: impl,
|
|
43990
|
+
hasRenderer: !!renderer,
|
|
43991
|
+
rendererType: renderer ? typeof renderer : 'undefined',
|
|
43992
|
+
state: msg.action?.state,
|
|
43993
|
+
});
|
|
43994
|
+
});
|
|
43886
43995
|
// If tool indicator is hidden AND there are no action cards to render, don't render anything
|
|
43887
|
-
// This prevents empty wrapper divs that cause layout jumping
|
|
43888
43996
|
if (!showToolIndicator && actionMessages.length === 0) {
|
|
43889
43997
|
return null;
|
|
43890
43998
|
}
|
|
43891
|
-
const badges =
|
|
43999
|
+
const badges = visibleMessages.map((message) => {
|
|
43892
44000
|
const toolName = message.toolExecuting || message.message.name || 'Tool';
|
|
43893
44001
|
const hasError = message.isError || false;
|
|
43894
|
-
const
|
|
43895
|
-
const actionStatus = actionState?.status;
|
|
43896
|
-
const terminalStatuses = ['completed', 'booked', 'scheduled', 'failed', 'cancelled', 'displaying', 'clicked'];
|
|
43897
|
-
const isTerminalStatus = actionStatus && terminalStatuses.includes(actionStatus);
|
|
43898
|
-
const isDone = message.action ? (message.action.done ?? isTerminalStatus ?? false) : !message.isStreaming;
|
|
43899
|
-
const isLoading = !isDone;
|
|
44002
|
+
const loading = isActionLoading(message);
|
|
43900
44003
|
return {
|
|
43901
44004
|
id: message.id,
|
|
43902
44005
|
name: toolName,
|
|
43903
|
-
status:
|
|
44006
|
+
status: loading ? 'loading' : hasError ? 'error' : 'completed',
|
|
43904
44007
|
};
|
|
43905
44008
|
});
|
|
43906
44009
|
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message tool", children: [showToolIndicator && jsxRuntimeExports.jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
|
|
43907
|
-
if (!message.action || !getActionRenderer)
|
|
44010
|
+
if (!message.action || !getActionRenderer) {
|
|
44011
|
+
console.log('[ToolMessageGroup] Skipping - no action or renderer:', { hasAction: !!message.action, hasGetRenderer: !!getActionRenderer });
|
|
43908
44012
|
return null;
|
|
44013
|
+
}
|
|
43909
44014
|
const renderer = getActionRenderer(message.action.implementation);
|
|
43910
|
-
if (!renderer)
|
|
44015
|
+
if (!renderer) {
|
|
44016
|
+
console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
|
|
43911
44017
|
return null;
|
|
43912
|
-
|
|
44018
|
+
}
|
|
44019
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant, onActionDismiss) }, `action-${message.id}`));
|
|
43913
44020
|
})] }));
|
|
43914
44021
|
};
|
|
43915
44022
|
|
|
@@ -43971,12 +44078,17 @@
|
|
|
43971
44078
|
};
|
|
43972
44079
|
|
|
43973
44080
|
const MessageList = (props) => {
|
|
43974
|
-
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, } = props;
|
|
44081
|
+
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onActionDismiss, onFeedback, onScrollStateChange, getActionRenderer, variant, } = props;
|
|
43975
44082
|
const containerRef = reactExports.useRef(null);
|
|
43976
44083
|
const messagesEndRef = reactExports.useRef(null);
|
|
43977
44084
|
const [showScrollButton, setShowScrollButton] = reactExports.useState(false);
|
|
43978
44085
|
const prevMessageCountRef = reactExports.useRef(0);
|
|
43979
|
-
const
|
|
44086
|
+
const visibleMessages = reactExports.useMemo(() => messages.filter((message) => !message.action?.hidden), [messages]);
|
|
44087
|
+
const hasActiveAction = reactExports.useMemo(() => {
|
|
44088
|
+
// Find the last tool message and check if its action is still active (not done)
|
|
44089
|
+
const lastToolMsg = [...visibleMessages].reverse().find(msg => msg.message.role === 'tool');
|
|
44090
|
+
return lastToolMsg?.action && lastToolMsg.action.done !== true;
|
|
44091
|
+
}, [visibleMessages]);
|
|
43980
44092
|
const checkScrollPosition = reactExports.useCallback(() => {
|
|
43981
44093
|
const c = containerRef.current;
|
|
43982
44094
|
if (!c)
|
|
@@ -43999,7 +44111,7 @@
|
|
|
43999
44111
|
const c = containerRef.current;
|
|
44000
44112
|
if (!c)
|
|
44001
44113
|
return;
|
|
44002
|
-
const count =
|
|
44114
|
+
const count = visibleMessages.length;
|
|
44003
44115
|
const isNew = count > prevMessageCountRef.current;
|
|
44004
44116
|
prevMessageCountRef.current = count;
|
|
44005
44117
|
if (count === 0) {
|
|
@@ -44010,17 +44122,33 @@
|
|
|
44010
44122
|
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
|
|
44011
44123
|
}
|
|
44012
44124
|
checkScrollPosition();
|
|
44013
|
-
}, [
|
|
44125
|
+
}, [visibleMessages, isTyping, checkScrollPosition]);
|
|
44014
44126
|
const groupedMessages = reactExports.useMemo(() => {
|
|
44127
|
+
console.log('[DEBUG MessageList] ========================================');
|
|
44128
|
+
console.log('[DEBUG MessageList] Processing messages:', visibleMessages.length);
|
|
44129
|
+
visibleMessages.forEach((m, i) => {
|
|
44130
|
+
console.log(`[DEBUG MessageList] Message ${i}:`, {
|
|
44131
|
+
id: m.id,
|
|
44132
|
+
role: m.message.role,
|
|
44133
|
+
hasAction: !!m.action,
|
|
44134
|
+
actionImpl: m.action?.implementation,
|
|
44135
|
+
content: (m.message.content || '').substring(0, 50),
|
|
44136
|
+
});
|
|
44137
|
+
});
|
|
44015
44138
|
const result = [];
|
|
44016
44139
|
let toolGroup = [];
|
|
44017
|
-
const flush = () => {
|
|
44018
|
-
|
|
44019
|
-
|
|
44020
|
-
|
|
44021
|
-
|
|
44022
|
-
|
|
44140
|
+
const flush = () => {
|
|
44141
|
+
if (toolGroup.length) {
|
|
44142
|
+
console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
|
|
44143
|
+
result.push({ type: 'tool-group', messages: [...toolGroup] });
|
|
44144
|
+
toolGroup = [];
|
|
44145
|
+
}
|
|
44146
|
+
};
|
|
44147
|
+
for (const m of visibleMessages) {
|
|
44148
|
+
if (m.message.role === 'tool') {
|
|
44149
|
+
console.log('[DEBUG MessageList] Adding to tool group:', m.id);
|
|
44023
44150
|
toolGroup.push(m);
|
|
44151
|
+
}
|
|
44024
44152
|
else if (m.message.role === 'user') {
|
|
44025
44153
|
flush();
|
|
44026
44154
|
result.push({ type: 'message', message: m });
|
|
@@ -44032,6 +44160,7 @@
|
|
|
44032
44160
|
flush();
|
|
44033
44161
|
result.push({ type: 'message', message: m });
|
|
44034
44162
|
}
|
|
44163
|
+
// Don't flush on empty assistant messages - let tools continue grouping
|
|
44035
44164
|
}
|
|
44036
44165
|
else {
|
|
44037
44166
|
flush();
|
|
@@ -44039,18 +44168,27 @@
|
|
|
44039
44168
|
}
|
|
44040
44169
|
}
|
|
44041
44170
|
flush();
|
|
44171
|
+
console.log('[DEBUG MessageList] Final grouped result:', result.length, 'items');
|
|
44172
|
+
result.forEach((item, i) => {
|
|
44173
|
+
if (item.type === 'tool-group') {
|
|
44174
|
+
console.log(`[DEBUG MessageList] Group ${i}: tool-group with ${item.messages.length} messages`);
|
|
44175
|
+
}
|
|
44176
|
+
else {
|
|
44177
|
+
console.log(`[DEBUG MessageList] Group ${i}: message (${item.message.message.role})`);
|
|
44178
|
+
}
|
|
44179
|
+
});
|
|
44042
44180
|
return result;
|
|
44043
|
-
}, [
|
|
44044
|
-
const hasSuggestions =
|
|
44181
|
+
}, [visibleMessages]);
|
|
44182
|
+
const hasSuggestions = visibleMessages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
|
|
44045
44183
|
const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
|
|
44046
44184
|
return (jsxRuntimeExports.jsxs("div", { ref: containerRef, className: "ai-chat-messages", role: "log", "aria-live": "polite", children: [showWelcome && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && jsxRuntimeExports.jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle }), welcomeMessage && jsxRuntimeExports.jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage }), hasSuggestions && jsxRuntimeExports.jsx(SuggestedQuestions, { questions: suggestedQuestions, onQuestionClick: onSuggestedQuestionClick })] })), groupedMessages.map((item, i) => {
|
|
44047
44185
|
if (item.type === 'tool-group') {
|
|
44048
|
-
return jsxRuntimeExports.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor }, `tg-${i}`);
|
|
44186
|
+
return (jsxRuntimeExports.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant, onActionDismiss: onActionDismiss }, `tg-${i}`));
|
|
44049
44187
|
}
|
|
44050
44188
|
const isLast = i === groupedMessages.length - 1;
|
|
44051
44189
|
const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
|
|
44052
44190
|
return (jsxRuntimeExports.jsxs(React.Fragment, { children: [jsxRuntimeExports.jsx(Message, { message: item.message, showTimestamp: showTimestamps, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }), hasFollowUp && onSuggestedQuestionClick && jsxRuntimeExports.jsx(FollowUpSuggestions, { suggestions: item.message.suggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })] }, item.message.id));
|
|
44053
|
-
}), isTyping && showTypingIndicator && !hasActiveAction &&
|
|
44191
|
+
}), isTyping && showTypingIndicator && !hasActiveAction && visibleMessages.length > 0 && jsxRuntimeExports.jsx(TypingIndicator, {}), jsxRuntimeExports.jsx("div", { ref: messagesEndRef })] }));
|
|
44054
44192
|
};
|
|
44055
44193
|
|
|
44056
44194
|
const ALLOWED_EXTENSIONS = ['.pdf', '.doc', '.docx', '.txt', '.md', '.csv'];
|
|
@@ -44064,7 +44202,7 @@
|
|
|
44064
44202
|
return (bytes / 1024).toFixed(1) + ' KB';
|
|
44065
44203
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
44066
44204
|
};
|
|
44067
|
-
const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, }) => {
|
|
44205
|
+
const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, }) => {
|
|
44068
44206
|
const [value, setValue] = reactExports.useState('');
|
|
44069
44207
|
const [selectedFiles, setSelectedFiles] = reactExports.useState([]);
|
|
44070
44208
|
const textareaRef = reactExports.useRef(null);
|
|
@@ -44099,10 +44237,14 @@
|
|
|
44099
44237
|
}
|
|
44100
44238
|
};
|
|
44101
44239
|
const canSend = value.trim() || selectedFiles.length > 0;
|
|
44102
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-item", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-info", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-name", children: file.name }), jsxRuntimeExports.jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsxRuntimeExports.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsxRuntimeExports.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntimeExports.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntimeExports.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" }) }) })] })), jsxRuntimeExports.jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 2, wrap: "soft", "aria-label": "Message input" }), jsxRuntimeExports.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntimeExports.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsxRuntimeExports.jsx("path", { d: "M12 19V5" }), jsxRuntimeExports.jsx("path", { d: "M5 12l7-7 7 7" })] }) })] })] }));
|
|
44240
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-item", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-file-info", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-file-name", children: file.name }), jsxRuntimeExports.jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsxRuntimeExports.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsxRuntimeExports.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsxRuntimeExports.jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsxRuntimeExports.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntimeExports.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" }) }) })] })), jsxRuntimeExports.jsx("textarea", { ref: textareaRef, className: "ai-chat-input", value: value, onChange: (e) => setValue(e.target.value), onKeyDown: handleKeyDown, placeholder: placeholder, disabled: disabled, rows: 2, wrap: "soft", "aria-label": "Message input" }), jsxRuntimeExports.jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxRuntimeExports.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsxRuntimeExports.jsx("path", { d: "M12 19V5" }), jsxRuntimeExports.jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy", children: [jsxRuntimeExports.jsx("span", { children: "AI-generated responses may be inaccurate." }), onDataPolicyClick && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [' ', jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Privacy Notice" })] }))] }))] }));
|
|
44103
44241
|
};
|
|
44104
44242
|
|
|
44105
|
-
|
|
44243
|
+
const CloseButton = ({ onClick, className = "", ariaLabel = "Close", }) => {
|
|
44244
|
+
return (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-close-btn ${className}`, onClick: onClick, "aria-label": ariaLabel, children: jsxRuntimeExports.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", stroke: "currentColor", strokeWidth: "2", children: jsxRuntimeExports.jsx("path", { d: "M1 1L13 13M1 13L13 1" }) }) }));
|
|
44245
|
+
};
|
|
44246
|
+
|
|
44247
|
+
function groupSlotsByDate$1(slots) {
|
|
44106
44248
|
const grouped = new Map();
|
|
44107
44249
|
for (const slot of slots) {
|
|
44108
44250
|
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
@@ -44116,7 +44258,7 @@
|
|
|
44116
44258
|
}
|
|
44117
44259
|
return grouped;
|
|
44118
44260
|
}
|
|
44119
|
-
function formatDate(dateStr) {
|
|
44261
|
+
function formatDate$1(dateStr) {
|
|
44120
44262
|
try {
|
|
44121
44263
|
const date = new Date(dateStr);
|
|
44122
44264
|
return new Intl.DateTimeFormat("en-US", {
|
|
@@ -44129,19 +44271,19 @@
|
|
|
44129
44271
|
return dateStr;
|
|
44130
44272
|
}
|
|
44131
44273
|
}
|
|
44132
|
-
function CalendarIcon() {
|
|
44274
|
+
function CalendarIcon$1() {
|
|
44133
44275
|
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }));
|
|
44134
44276
|
}
|
|
44135
|
-
function CheckIcon() {
|
|
44277
|
+
function CheckIcon$1() {
|
|
44136
44278
|
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }));
|
|
44137
44279
|
}
|
|
44138
|
-
function ExternalLinkIcon$
|
|
44280
|
+
function ExternalLinkIcon$2() {
|
|
44139
44281
|
return (jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
44140
44282
|
}
|
|
44141
|
-
function Skeleton({ width, height, borderRadius = '4px' }) {
|
|
44283
|
+
function Skeleton$2({ width, height, borderRadius = '4px' }) {
|
|
44142
44284
|
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
44143
44285
|
}
|
|
44144
|
-
function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
|
|
44286
|
+
function GoogleCalendarCard({ action, onComplete, onDismiss, accentColor, className = '' }) {
|
|
44145
44287
|
const state = action.state;
|
|
44146
44288
|
const rawSlots = state.availableSlots;
|
|
44147
44289
|
const availableSlots = Array.isArray(rawSlots)
|
|
@@ -44155,13 +44297,12 @@
|
|
|
44155
44297
|
: [];
|
|
44156
44298
|
const allowTopic = state.allowTopic !== false;
|
|
44157
44299
|
const isBooked = state.status === "booked";
|
|
44158
|
-
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
44300
|
+
const slotsByDate = groupSlotsByDate$1(availableSlots);
|
|
44159
44301
|
const dates = Array.from(slotsByDate.keys()).sort();
|
|
44160
44302
|
const [selectedDate, setSelectedDate] = reactExports.useState(dates[0] ?? "");
|
|
44161
44303
|
const [selectedSlot, setSelectedSlot] = reactExports.useState(null);
|
|
44162
44304
|
const [topic, setTopic] = reactExports.useState("");
|
|
44163
44305
|
const [error, setError] = reactExports.useState(null);
|
|
44164
|
-
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
44165
44306
|
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
44166
44307
|
const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
|
|
44167
44308
|
const onConfirm = () => {
|
|
@@ -44174,8 +44315,252 @@
|
|
|
44174
44315
|
return;
|
|
44175
44316
|
}
|
|
44176
44317
|
setError(null);
|
|
44318
|
+
onComplete?.(action.toolCallId, {
|
|
44319
|
+
...action.state,
|
|
44320
|
+
selectedSlot: {
|
|
44321
|
+
startTime: selectedSlot.startTime,
|
|
44322
|
+
endTime: selectedSlot.endTime,
|
|
44323
|
+
},
|
|
44324
|
+
topic: allowTopic ? topic.trim() : null,
|
|
44325
|
+
});
|
|
44326
|
+
};
|
|
44327
|
+
const handleDismiss = () => {
|
|
44328
|
+
onDismiss?.(action.toolCallId);
|
|
44329
|
+
};
|
|
44330
|
+
// Booked state
|
|
44331
|
+
if (isBooked) {
|
|
44332
|
+
const bookedSlot = state.selectedSlot;
|
|
44333
|
+
const bookedTopic = state.topic;
|
|
44334
|
+
const eventLink = state.bookedEventLink;
|
|
44335
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntimeExports.jsx(CheckIcon$1, {}) }), "Appointment Confirmed"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxRuntimeExports.jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsxRuntimeExports.jsx(ExternalLinkIcon$2, {})] }))] })] }));
|
|
44336
|
+
}
|
|
44337
|
+
// Skeleton loading state - show when waiting for backend after user confirms
|
|
44338
|
+
const isWaitingForBackend = !action.done && state.selectedSlot && !isBooked;
|
|
44339
|
+
if (isWaitingForBackend) {
|
|
44340
|
+
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntimeExports.jsx(Skeleton$2, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntimeExports.jsx(Skeleton$2, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton$2, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton$2, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton$2, { width: "50px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton$2, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsx(Skeleton$2, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
44341
|
+
}
|
|
44342
|
+
// Booking form
|
|
44343
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ai-chat-google-calendar ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon$1, {}), "Schedule an Appointment", onDismiss && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsxRuntimeExports.jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
|
|
44344
|
+
setSelectedDate(date);
|
|
44345
|
+
setSelectedSlot(null);
|
|
44346
|
+
}, children: formatDate$1(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), error && jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: error }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
|
|
44347
|
+
}
|
|
44348
|
+
|
|
44349
|
+
function groupSlotsByDate(slots) {
|
|
44350
|
+
const grouped = new Map();
|
|
44351
|
+
for (const slot of slots) {
|
|
44352
|
+
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
44353
|
+
continue;
|
|
44354
|
+
}
|
|
44355
|
+
const date = slot.startTime.slice(0, 10);
|
|
44356
|
+
if (!grouped.has(date)) {
|
|
44357
|
+
grouped.set(date, []);
|
|
44358
|
+
}
|
|
44359
|
+
grouped.get(date).push(slot);
|
|
44360
|
+
}
|
|
44361
|
+
return grouped;
|
|
44362
|
+
}
|
|
44363
|
+
function formatDate(dateStr) {
|
|
44364
|
+
try {
|
|
44365
|
+
const date = new Date(dateStr);
|
|
44366
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
44367
|
+
weekday: "short",
|
|
44368
|
+
month: "short",
|
|
44369
|
+
day: "numeric",
|
|
44370
|
+
}).format(date);
|
|
44371
|
+
}
|
|
44372
|
+
catch {
|
|
44373
|
+
return dateStr;
|
|
44374
|
+
}
|
|
44375
|
+
}
|
|
44376
|
+
function CalendarIcon() {
|
|
44377
|
+
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }));
|
|
44378
|
+
}
|
|
44379
|
+
function MailIcon() {
|
|
44380
|
+
return (jsxRuntimeExports.jsxs("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: [jsxRuntimeExports.jsx("path", { d: "M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" }), jsxRuntimeExports.jsx("path", { d: "M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" })] }));
|
|
44381
|
+
}
|
|
44382
|
+
function CheckIcon() {
|
|
44383
|
+
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }));
|
|
44384
|
+
}
|
|
44385
|
+
function ErrorIcon() {
|
|
44386
|
+
return (jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon-error", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }));
|
|
44387
|
+
}
|
|
44388
|
+
function ExternalLinkIcon$1() {
|
|
44389
|
+
return (jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
44390
|
+
}
|
|
44391
|
+
function Skeleton$1({ width, height, borderRadius = '4px' }) {
|
|
44392
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
44393
|
+
}
|
|
44394
|
+
function PinInputGroup$1({ values, onChange, disabled }) {
|
|
44395
|
+
const inputRefs = reactExports.useRef([]);
|
|
44396
|
+
const handleChange = (index, value) => {
|
|
44397
|
+
// Only allow digits
|
|
44398
|
+
const digit = value.replace(/[^0-9]/g, '');
|
|
44399
|
+
const newValues = [...values];
|
|
44400
|
+
newValues[index] = digit.slice(-1);
|
|
44401
|
+
onChange(newValues);
|
|
44402
|
+
// Auto-focus next input
|
|
44403
|
+
if (digit && index < 5) {
|
|
44404
|
+
inputRefs.current[index + 1]?.focus();
|
|
44405
|
+
}
|
|
44406
|
+
};
|
|
44407
|
+
const handleKeyDown = (index, e) => {
|
|
44408
|
+
if (e.key === 'Backspace' && !values[index] && index > 0) {
|
|
44409
|
+
inputRefs.current[index - 1]?.focus();
|
|
44410
|
+
}
|
|
44411
|
+
};
|
|
44412
|
+
const handlePaste = (e) => {
|
|
44413
|
+
e.preventDefault();
|
|
44414
|
+
const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
|
|
44415
|
+
const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
|
|
44416
|
+
onChange(newValues);
|
|
44417
|
+
// Focus the next empty input or the last one
|
|
44418
|
+
const nextIndex = Math.min(pastedData.length, 5);
|
|
44419
|
+
inputRefs.current[nextIndex]?.focus();
|
|
44420
|
+
};
|
|
44421
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsxRuntimeExports.jsx("input", { ref: (el) => {
|
|
44422
|
+
inputRefs.current[index] = el;
|
|
44423
|
+
}, type: "text", inputMode: "numeric", maxLength: 1, className: "ai-chat-pin-input", value: value, onChange: (e) => handleChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), onPaste: handlePaste, disabled: disabled, autoFocus: index === 0 }, index))) }));
|
|
44424
|
+
}
|
|
44425
|
+
function MicrosoftCalendarCard({ action, onComplete, onDismiss, accentColor, className = '' }) {
|
|
44426
|
+
const state = action.state;
|
|
44427
|
+
const phase = state.phase || "awaiting_email";
|
|
44428
|
+
const allowTopic = state.allowTopic !== false;
|
|
44429
|
+
const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
|
|
44430
|
+
const handleDismiss = () => {
|
|
44431
|
+
onDismiss?.(action.toolCallId);
|
|
44432
|
+
};
|
|
44433
|
+
const showCloseButton = Boolean(onDismiss);
|
|
44434
|
+
// Debug: Log state changes
|
|
44435
|
+
const prevStateRef = reactExports.useRef(null);
|
|
44436
|
+
reactExports.useEffect(() => {
|
|
44437
|
+
if (JSON.stringify(prevStateRef.current) !== JSON.stringify(state)) {
|
|
44438
|
+
console.log('[MicrosoftCalendarCard] State updated:', {
|
|
44439
|
+
phase: state.phase,
|
|
44440
|
+
hasError: !!state.errorMessage,
|
|
44441
|
+
error: state.errorMessage,
|
|
44442
|
+
slotsCount: state.availableSlots?.length || 0
|
|
44443
|
+
});
|
|
44444
|
+
prevStateRef.current = state;
|
|
44445
|
+
}
|
|
44446
|
+
}, [state]);
|
|
44447
|
+
// Email phase state
|
|
44448
|
+
const [email, setEmail] = reactExports.useState("");
|
|
44449
|
+
const [emailError, setEmailError] = reactExports.useState(null);
|
|
44450
|
+
// OTP phase state
|
|
44451
|
+
const [otpValues, setOtpValues] = reactExports.useState(Array(6).fill(''));
|
|
44452
|
+
const [otpError, setOtpError] = reactExports.useState(null);
|
|
44453
|
+
// Loading states
|
|
44454
|
+
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
44455
|
+
// Reset loading state when phase changes (backend has responded)
|
|
44456
|
+
// Use useEffect for reliable re-rendering
|
|
44457
|
+
reactExports.useEffect(() => {
|
|
44458
|
+
console.log('[MicrosoftCalendarCard] Phase changed to:', phase);
|
|
44459
|
+
setIsSubmitting(false);
|
|
44460
|
+
// Clear errors when transitioning to new phase
|
|
44461
|
+
if (phase === "awaiting_email") {
|
|
44462
|
+
setEmailError(null);
|
|
44463
|
+
setOtpError(null);
|
|
44464
|
+
setSelectionError(null);
|
|
44465
|
+
}
|
|
44466
|
+
else if (phase === "awaiting_otp") {
|
|
44467
|
+
setOtpError(state.errorMessage || null);
|
|
44468
|
+
setEmailError(null);
|
|
44469
|
+
setSelectionError(null);
|
|
44470
|
+
// Clear OTP input for fresh attempt
|
|
44471
|
+
setOtpValues(Array(6).fill(''));
|
|
44472
|
+
}
|
|
44473
|
+
else if (phase === "awaiting_options") {
|
|
44474
|
+
setEmailError(null);
|
|
44475
|
+
setOtpError(null);
|
|
44476
|
+
setSelectionError(null);
|
|
44477
|
+
}
|
|
44478
|
+
else if (phase === "awaiting_booking") {
|
|
44479
|
+
setSelectionError(state.errorMessage || null);
|
|
44480
|
+
setEmailError(null);
|
|
44481
|
+
setOtpError(null);
|
|
44482
|
+
}
|
|
44483
|
+
else if (phase === "booked" || phase === "cancelled" || phase === "error") {
|
|
44484
|
+
setEmailError(null);
|
|
44485
|
+
setOtpError(null);
|
|
44486
|
+
setSelectionError(null);
|
|
44487
|
+
setSelectedId(null); // Reset selection
|
|
44488
|
+
}
|
|
44489
|
+
}, [phase, state.errorMessage]);
|
|
44490
|
+
// Selection phase state
|
|
44491
|
+
const rawSlots = state.availableSlots;
|
|
44492
|
+
const availableSlots = Array.isArray(rawSlots)
|
|
44493
|
+
? rawSlots.filter((slot) => slot !== null &&
|
|
44494
|
+
slot !== undefined &&
|
|
44495
|
+
typeof slot === "object" &&
|
|
44496
|
+
"startTime" in slot &&
|
|
44497
|
+
"endTime" in slot &&
|
|
44498
|
+
typeof slot.startTime === "string" &&
|
|
44499
|
+
typeof slot.endTime === "string")
|
|
44500
|
+
: [];
|
|
44501
|
+
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
44502
|
+
const dates = Array.from(slotsByDate.keys()).sort();
|
|
44503
|
+
const [selectedDate, setSelectedDate] = reactExports.useState(dates[0] ?? "");
|
|
44504
|
+
const [selectedSlot, setSelectedSlot] = reactExports.useState(null);
|
|
44505
|
+
const [topic, setTopic] = reactExports.useState("");
|
|
44506
|
+
const [selectionError, setSelectionError] = reactExports.useState(null);
|
|
44507
|
+
// Cancellation phase state
|
|
44508
|
+
const [selectedId, setSelectedId] = reactExports.useState(null);
|
|
44509
|
+
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
44510
|
+
// Phase 1: Email Input
|
|
44511
|
+
const handleEmailSubmit = () => {
|
|
44512
|
+
const trimmedEmail = email.trim();
|
|
44513
|
+
if (!trimmedEmail) {
|
|
44514
|
+
setEmailError("Please enter your email address");
|
|
44515
|
+
return;
|
|
44516
|
+
}
|
|
44517
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
|
|
44518
|
+
setEmailError("Please enter a valid email address");
|
|
44519
|
+
return;
|
|
44520
|
+
}
|
|
44521
|
+
setEmailError(null);
|
|
44522
|
+
setIsSubmitting(true);
|
|
44523
|
+
console.log('[MicrosoftCalendarCard] Submitting email:', trimmedEmail);
|
|
44524
|
+
setTimeout(() => {
|
|
44525
|
+
onComplete?.(action.toolCallId, {
|
|
44526
|
+
...action.state,
|
|
44527
|
+
email: trimmedEmail,
|
|
44528
|
+
});
|
|
44529
|
+
}, 50);
|
|
44530
|
+
};
|
|
44531
|
+
// Phase 2: OTP Verification
|
|
44532
|
+
const handleOtpSubmit = () => {
|
|
44533
|
+
const otpCode = otpValues.join('');
|
|
44534
|
+
if (otpCode.length !== 6) {
|
|
44535
|
+
setOtpError("Please enter the 6-digit code");
|
|
44536
|
+
return;
|
|
44537
|
+
}
|
|
44538
|
+
setOtpError(null);
|
|
44539
|
+
setIsSubmitting(true);
|
|
44540
|
+
console.log('[MicrosoftCalendarCard] Submitting OTP code');
|
|
44541
|
+
setTimeout(() => {
|
|
44542
|
+
onComplete?.(action.toolCallId, {
|
|
44543
|
+
...action.state,
|
|
44544
|
+
otpCode,
|
|
44545
|
+
});
|
|
44546
|
+
}, 50);
|
|
44547
|
+
};
|
|
44548
|
+
// Phase 3: Appointment Selection
|
|
44549
|
+
const handleAppointmentConfirm = () => {
|
|
44550
|
+
if (!selectedSlot) {
|
|
44551
|
+
setSelectionError("Please select a time slot");
|
|
44552
|
+
return;
|
|
44553
|
+
}
|
|
44554
|
+
if (allowTopic && !topic.trim()) {
|
|
44555
|
+
setSelectionError("Please enter a meeting topic");
|
|
44556
|
+
return;
|
|
44557
|
+
}
|
|
44558
|
+
setSelectionError(null);
|
|
44177
44559
|
setIsSubmitting(true);
|
|
44178
|
-
|
|
44560
|
+
console.log('[MicrosoftCalendarCard] Confirming appointment:', {
|
|
44561
|
+
slot: selectedSlot,
|
|
44562
|
+
topic: topic.trim()
|
|
44563
|
+
});
|
|
44179
44564
|
setTimeout(() => {
|
|
44180
44565
|
onComplete?.(action.toolCallId, {
|
|
44181
44566
|
...action.state,
|
|
@@ -44187,22 +44572,149 @@
|
|
|
44187
44572
|
});
|
|
44188
44573
|
}, 50);
|
|
44189
44574
|
};
|
|
44190
|
-
//
|
|
44191
|
-
|
|
44575
|
+
// Handle "Use different email" button
|
|
44576
|
+
const handleUseDifferentEmail = () => {
|
|
44577
|
+
setEmail("");
|
|
44578
|
+
setEmailError(null);
|
|
44579
|
+
setOtpValues(Array(6).fill(''));
|
|
44580
|
+
setOtpError(null);
|
|
44581
|
+
onComplete?.(action.toolCallId, {
|
|
44582
|
+
phase: "awaiting_email",
|
|
44583
|
+
email: null,
|
|
44584
|
+
otpVerified: false,
|
|
44585
|
+
otpAttempts: 0,
|
|
44586
|
+
availableSlots: [],
|
|
44587
|
+
selectedSlot: null,
|
|
44588
|
+
topic: null,
|
|
44589
|
+
bookedEventId: null,
|
|
44590
|
+
bookedEventLink: null,
|
|
44591
|
+
allowTopic,
|
|
44592
|
+
errorMessage: null,
|
|
44593
|
+
});
|
|
44594
|
+
};
|
|
44595
|
+
// Phase 5: Booked Confirmation
|
|
44596
|
+
if (phase === "booked") {
|
|
44192
44597
|
const bookedSlot = state.selectedSlot;
|
|
44193
44598
|
const bookedTopic = state.topic;
|
|
44194
44599
|
const eventLink = state.bookedEventLink;
|
|
44195
|
-
|
|
44196
|
-
|
|
44197
|
-
|
|
44600
|
+
const bookedEmail = state.email;
|
|
44601
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntimeExports.jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), bookedEmail && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-hint", children: ["A calendar invitation has been sent to ", bookedEmail] })), eventLink && (jsxRuntimeExports.jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Outlook Calendar", jsxRuntimeExports.jsx(ExternalLinkIcon$1, {})] }))] })] }));
|
|
44602
|
+
}
|
|
44603
|
+
// Phase 6: Cancelled Confirmation
|
|
44604
|
+
if (phase === "cancelled") {
|
|
44605
|
+
const cancelledSubject = state.cancelledEventSubject;
|
|
44606
|
+
const userEmail = state.email;
|
|
44607
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsxRuntimeExports.jsx(CheckIcon, {}) }), "Appointment Cancelled"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [cancelledSubject && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail-box", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label-small", children: "CANCELLED" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value-large", children: cancelledSubject })] })), userEmail && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-hint", children: ["A cancellation notice has been sent to ", userEmail] }))] })] }));
|
|
44608
|
+
}
|
|
44609
|
+
// Error State
|
|
44610
|
+
if (phase === "error") {
|
|
44611
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-error ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(ErrorIcon, {}), "Error"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error-message", children: state.errorMessage || "An error occurred. Please try again." }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
44612
|
+
setEmail("");
|
|
44613
|
+
setEmailError(null);
|
|
44614
|
+
setOtpValues(Array(6).fill(''));
|
|
44615
|
+
setOtpError(null);
|
|
44616
|
+
onComplete?.(action.toolCallId, {
|
|
44617
|
+
phase: "awaiting_email",
|
|
44618
|
+
email: null,
|
|
44619
|
+
otpVerified: false,
|
|
44620
|
+
otpAttempts: 0,
|
|
44621
|
+
availableSlots: [],
|
|
44622
|
+
selectedSlot: null,
|
|
44623
|
+
topic: null,
|
|
44624
|
+
bookedEventId: null,
|
|
44625
|
+
bookedEventLink: null,
|
|
44626
|
+
allowTopic,
|
|
44627
|
+
errorMessage: null,
|
|
44628
|
+
});
|
|
44629
|
+
}, children: "Start Over" })] })] }));
|
|
44630
|
+
}
|
|
44631
|
+
// Loading State
|
|
44198
44632
|
if (isSubmitting) {
|
|
44199
|
-
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntimeExports.jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntimeExports.jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.
|
|
44200
|
-
}
|
|
44201
|
-
//
|
|
44202
|
-
|
|
44203
|
-
|
|
44204
|
-
|
|
44205
|
-
|
|
44633
|
+
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntimeExports.jsx(Skeleton$1, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntimeExports.jsx(Skeleton$1, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton$1, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton$1, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsx(Skeleton$1, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
44634
|
+
}
|
|
44635
|
+
// Phase 1: Email Input
|
|
44636
|
+
if (phase === "awaiting_email") {
|
|
44637
|
+
const displayError = state.errorMessage || emailError;
|
|
44638
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Schedule an Appointment", showCloseButton && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "We'll send a verification code to your email" }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { htmlFor: `email-${action.toolCallId}`, className: "ai-chat-action-label", children: "Email Address" }), jsxRuntimeExports.jsx("input", { id: `email-${action.toolCallId}`, type: "email", className: "ai-chat-action-input", placeholder: "your@email.com", value: email, onChange: (e) => {
|
|
44639
|
+
setEmail(e.target.value);
|
|
44640
|
+
setEmailError(null);
|
|
44641
|
+
}, onKeyPress: (e) => {
|
|
44642
|
+
if (e.key === 'Enter') {
|
|
44643
|
+
handleEmailSubmit();
|
|
44644
|
+
}
|
|
44645
|
+
}, autoFocus: true })] }), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleEmailSubmit, children: "Continue" })] })] }));
|
|
44646
|
+
}
|
|
44647
|
+
// Phase 2: OTP Input
|
|
44648
|
+
if (phase === "awaiting_otp") {
|
|
44649
|
+
const displayError = state.errorMessage || otpError;
|
|
44650
|
+
const userEmail = state.email;
|
|
44651
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(MailIcon, {}), "Verify Your Email", showCloseButton && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-hint", children: ["We sent a 6-digit code to ", jsxRuntimeExports.jsx("strong", { children: userEmail })] }), jsxRuntimeExports.jsx(PinInputGroup$1, { values: otpValues, onChange: (newValues) => {
|
|
44652
|
+
setOtpValues(newValues);
|
|
44653
|
+
setOtpError(null);
|
|
44654
|
+
// Auto-submit when all 6 digits are entered
|
|
44655
|
+
if (newValues.every(v => v.length === 1)) {
|
|
44656
|
+
console.log('[MicrosoftCalendarCard] Auto-submitting OTP (all 6 digits entered)');
|
|
44657
|
+
setIsSubmitting(true);
|
|
44658
|
+
const code = newValues.join('');
|
|
44659
|
+
setTimeout(() => {
|
|
44660
|
+
onComplete?.(action.toolCallId, {
|
|
44661
|
+
...action.state,
|
|
44662
|
+
otpCode: code,
|
|
44663
|
+
});
|
|
44664
|
+
}, 100);
|
|
44665
|
+
}
|
|
44666
|
+
}, disabled: isSubmitting }), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, children: "Verify Code" }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: handleUseDifferentEmail, children: "Use different email" })] })] }));
|
|
44667
|
+
}
|
|
44668
|
+
// Phase 3: Options Menu (with inline cancel buttons and confirmation)
|
|
44669
|
+
if (phase === "awaiting_options") {
|
|
44670
|
+
const userAppointments = state.userAppointments || [];
|
|
44671
|
+
const maxAppointments = state.maxAppointmentsPerUser || 3;
|
|
44672
|
+
const appointmentCount = userAppointments.length;
|
|
44673
|
+
const canBook = appointmentCount < maxAppointments;
|
|
44674
|
+
const hasAppointments = appointmentCount > 0;
|
|
44675
|
+
const displayError = state.errorMessage || selectionError;
|
|
44676
|
+
// If confirming cancellation, show confirmation dialog
|
|
44677
|
+
if (selectedId) {
|
|
44678
|
+
const appointmentToCancel = userAppointments.find(appt => appt.id === selectedId);
|
|
44679
|
+
if (!appointmentToCancel) {
|
|
44680
|
+
setSelectedId(null); // Reset if appointment not found
|
|
44681
|
+
}
|
|
44682
|
+
else {
|
|
44683
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Confirm Cancellation", showCloseButton && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "Are you sure you want to cancel this appointment?" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-item", style: { marginBottom: '16px' }, children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-subject", children: appointmentToCancel.subject }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-time", children: appointmentToCancel.displayTime })] }) }), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-button-group", children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
|
|
44684
|
+
setIsSubmitting(true);
|
|
44685
|
+
onComplete?.(action.toolCallId, {
|
|
44686
|
+
...action.state,
|
|
44687
|
+
selectedOption: "cancel",
|
|
44688
|
+
selectedAppointmentId: selectedId,
|
|
44689
|
+
});
|
|
44690
|
+
}, disabled: isSubmitting, children: isSubmitting ? 'Cancelling...' : 'Confirm Cancellation' }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
44691
|
+
setSelectedId(null);
|
|
44692
|
+
setSelectionError(null);
|
|
44693
|
+
}, disabled: isSubmitting, children: "Go Back" })] })] })] }));
|
|
44694
|
+
}
|
|
44695
|
+
}
|
|
44696
|
+
// Normal view with inline cancel buttons
|
|
44697
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Manage Your Appointments", showCloseButton && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-hint", children: ["You have ", appointmentCount, " active appointment", appointmentCount !== 1 ? 's' : '', canBook && ` (${maxAppointments - appointmentCount} slot${maxAppointments - appointmentCount !== 1 ? 's' : ''} remaining)`] }), hasAppointments && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-list", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-label", children: "Your Upcoming Appointments" }), userAppointments.map((appt) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-item", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-subject", children: appt.subject }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-appointment-time", children: appt.displayTime })] }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
44698
|
+
setSelectedId(appt.id);
|
|
44699
|
+
setSelectionError(null);
|
|
44700
|
+
}, children: "Cancel" })] }, appt.id)))] })), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), canBook && (jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
|
|
44701
|
+
setIsSubmitting(true);
|
|
44702
|
+
onComplete?.(action.toolCallId, {
|
|
44703
|
+
...action.state,
|
|
44704
|
+
selectedOption: "book",
|
|
44705
|
+
});
|
|
44706
|
+
}, disabled: isSubmitting, children: isSubmitting ? 'Loading...' : 'Book New Appointment' })), !canBook && !hasAppointments && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "No appointments found." }))] })] }));
|
|
44707
|
+
}
|
|
44708
|
+
// Phase 4: Appointment Selection (Booking)
|
|
44709
|
+
if (phase === "awaiting_booking") {
|
|
44710
|
+
const displayError = state.errorMessage || selectionError;
|
|
44711
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-action-card--closable ${className}`, style: accentStyle, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx(CalendarIcon, {}), "Select Appointment Time", showCloseButton && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Cancel appointment booking" }))] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsxRuntimeExports.jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
|
|
44712
|
+
setSelectedDate(date);
|
|
44713
|
+
setSelectedSlot(null);
|
|
44714
|
+
}, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), displayError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleAppointmentConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
|
|
44715
|
+
}
|
|
44716
|
+
// Fallback
|
|
44717
|
+
return null;
|
|
44206
44718
|
}
|
|
44207
44719
|
|
|
44208
44720
|
function truncate(text, maxLength) {
|
|
@@ -44213,17 +44725,30 @@
|
|
|
44213
44725
|
function ExternalLinkIcon() {
|
|
44214
44726
|
return (jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsxRuntimeExports.jsx("polyline", { points: "15 3 21 3 21 9" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
44215
44727
|
}
|
|
44728
|
+
function SingleLinkPreview({ link, onLinkClick, accentColor }) {
|
|
44729
|
+
const domain = (() => {
|
|
44730
|
+
if (!link.url)
|
|
44731
|
+
return '';
|
|
44732
|
+
try {
|
|
44733
|
+
return new URL(link.url).hostname.replace('www.', '');
|
|
44734
|
+
}
|
|
44735
|
+
catch {
|
|
44736
|
+
return link.url;
|
|
44737
|
+
}
|
|
44738
|
+
})();
|
|
44739
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
44740
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-card ai-chat-link-preview", onClick: onLinkClick, style: style, role: "link", tabIndex: 0, onKeyDown: (e) => e.key === 'Enter' && onLinkClick(), children: [link.image && (jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview__image", children: jsxRuntimeExports.jsx("img", { src: link.image, alt: link.title, onError: (e) => {
|
|
44741
|
+
e.currentTarget.parentElement.style.display = 'none';
|
|
44742
|
+
} }) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview__site", children: [link.favicon && (jsxRuntimeExports.jsx("img", { src: link.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
|
|
44743
|
+
e.currentTarget.style.display = 'none';
|
|
44744
|
+
} })), jsxRuntimeExports.jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsxRuntimeExports.jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__description", children: truncate(link.description, 120) }))] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview__arrow", children: jsxRuntimeExports.jsx(ExternalLinkIcon, {}) })] }));
|
|
44745
|
+
}
|
|
44216
44746
|
function LinkPreviewCard({ action, onComplete, accentColor }) {
|
|
44217
44747
|
const rawState = action.state;
|
|
44218
44748
|
const hasCompletedRef = reactExports.useRef(false);
|
|
44219
44749
|
// Provide safe defaults if state is missing
|
|
44220
44750
|
const state = {
|
|
44221
|
-
|
|
44222
|
-
title: rawState?.title || 'Link',
|
|
44223
|
-
description: rawState?.description,
|
|
44224
|
-
image: rawState?.image,
|
|
44225
|
-
siteName: rawState?.siteName,
|
|
44226
|
-
favicon: rawState?.favicon,
|
|
44751
|
+
links: rawState?.links || [],
|
|
44227
44752
|
context: rawState?.context,
|
|
44228
44753
|
status: rawState?.status || 'displaying',
|
|
44229
44754
|
error: rawState?.error,
|
|
@@ -44231,34 +44756,29 @@
|
|
|
44231
44756
|
const isError = state.status === 'error';
|
|
44232
44757
|
// Auto-complete on mount so AI can continue generating text response
|
|
44233
44758
|
reactExports.useEffect(() => {
|
|
44234
|
-
if (!action.done && !hasCompletedRef.current && onComplete && state.
|
|
44759
|
+
if (!action.done && !hasCompletedRef.current && onComplete && state.links.length > 0) {
|
|
44235
44760
|
hasCompletedRef.current = true;
|
|
44236
44761
|
// Signal completion immediately - the card is displayed, AI can continue
|
|
44237
44762
|
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
44238
44763
|
}
|
|
44239
44764
|
}, [action.done, action.toolCallId, onComplete, state]);
|
|
44240
|
-
const
|
|
44241
|
-
if (
|
|
44242
|
-
window.open(
|
|
44765
|
+
const handleLinkClick = (url) => {
|
|
44766
|
+
if (url) {
|
|
44767
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
44243
44768
|
}
|
|
44244
44769
|
onComplete?.(action.toolCallId, { ...state, status: 'clicked' });
|
|
44245
44770
|
};
|
|
44246
|
-
|
|
44247
|
-
|
|
44248
|
-
|
|
44249
|
-
|
|
44250
|
-
|
|
44251
|
-
|
|
44252
|
-
|
|
44253
|
-
|
|
44254
|
-
|
|
44255
|
-
|
|
44256
|
-
|
|
44257
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-link-preview ${isError ? 'ai-chat-link-preview--error' : ''}`, onClick: handleClick, style: style, role: "link", tabIndex: 0, onKeyDown: (e) => e.key === 'Enter' && handleClick(), children: [state.image && !isError && (jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview__image", children: jsxRuntimeExports.jsx("img", { src: state.image, alt: state.title, onError: (e) => {
|
|
44258
|
-
e.currentTarget.parentElement.style.display = 'none';
|
|
44259
|
-
} }) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview__site", children: [state.favicon && (jsxRuntimeExports.jsx("img", { src: state.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
|
|
44260
|
-
e.currentTarget.style.display = 'none';
|
|
44261
|
-
} })), jsxRuntimeExports.jsx("span", { className: "ai-chat-link-preview__domain", children: state.siteName || domain })] }), jsxRuntimeExports.jsx("h4", { className: "ai-chat-link-preview__title", children: state.title }), state.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__description", children: truncate(state.description, 120) })), state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__context", children: state.context })), isError && state.error && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error }))] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview__arrow", children: jsxRuntimeExports.jsx(ExternalLinkIcon, {}) })] }));
|
|
44771
|
+
if (isError) {
|
|
44772
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-card ai-chat-link-preview ai-chat-link-preview--error", children: jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview__content", children: jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error || 'Failed to load preview' }) }) }));
|
|
44773
|
+
}
|
|
44774
|
+
if (state.links.length === 0) {
|
|
44775
|
+
return null;
|
|
44776
|
+
}
|
|
44777
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-link-preview-container", children: [state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-link-preview__context", style: { marginBottom: '8px', fontSize: '0.9em', color: 'var(--ai-chat-fg-muted)' }, children: state.context })), jsxRuntimeExports.jsx("div", { className: "ai-chat-link-preview-grid", style: {
|
|
44778
|
+
display: 'grid',
|
|
44779
|
+
gridTemplateColumns: state.links.length === 1 ? '1fr' : state.links.length === 2 ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)',
|
|
44780
|
+
gap: '12px',
|
|
44781
|
+
}, children: state.links.map((link, index) => (jsxRuntimeExports.jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
|
|
44262
44782
|
}
|
|
44263
44783
|
|
|
44264
44784
|
function PlayIcon() {
|
|
@@ -44324,7 +44844,7 @@
|
|
|
44324
44844
|
return src;
|
|
44325
44845
|
}
|
|
44326
44846
|
};
|
|
44327
|
-
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-
|
|
44847
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-card ai-chat-video-player", style: style, children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-video-player__container", children: isError ? (jsxRuntimeExports.jsx("div", { className: "ai-chat-video-player__error", children: jsxRuntimeExports.jsx("span", { children: state.error || 'Could not load video' }) })) : !isPlaying && state.thumbnailUrl ? (jsxRuntimeExports.jsxs("div", { className: "ai-chat-video-player__thumbnail", onClick: handlePlay, children: [jsxRuntimeExports.jsx("img", { src: state.thumbnailUrl, alt: state.title || 'Video thumbnail' }), jsxRuntimeExports.jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsxRuntimeExports.jsx(PlayIcon, {}) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : !isPlaying ? (jsxRuntimeExports.jsxs("div", { className: "ai-chat-video-player__placeholder", onClick: handlePlay, children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsxRuntimeExports.jsx(PlayIcon, {}) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-video-player__click-text", children: "Click to play" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : state.provider === 'direct' ? (jsxRuntimeExports.jsx("video", { src: state.embedUrl, controls: true, autoPlay: true, className: "ai-chat-video-player__video" })) : (jsxRuntimeExports.jsx("iframe", { src: getEmbedSrc(), className: "ai-chat-video-player__iframe", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share", allowFullScreen: true, title: state.title || 'Video player' })) }), state.context && (jsxRuntimeExports.jsx("div", { className: "ai-chat-video-player__context", children: state.context }))] }));
|
|
44328
44848
|
}
|
|
44329
44849
|
|
|
44330
44850
|
function MapPinIcon() {
|
|
@@ -44385,7 +44905,9 @@
|
|
|
44385
44905
|
}
|
|
44386
44906
|
};
|
|
44387
44907
|
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
44388
|
-
|
|
44908
|
+
// Use smaller map height in compact mode
|
|
44909
|
+
const effectiveMapHeight = compact ? Math.min(mapHeight, 140) : mapHeight;
|
|
44910
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && settings.showMap !== false && (jsxRuntimeExports.jsx("div", { className: "ai-chat-location-card__map", style: { height: effectiveMapHeight }, children: jsxRuntimeExports.jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card__content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card__header", children: [jsxRuntimeExports.jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsxRuntimeExports.jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsxRuntimeExports.jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxRuntimeExports.jsxs("p", { className: "ai-chat-location-card__address", children: [jsxRuntimeExports.jsx(MapPinIcon, {}), location.address] }), location.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsxRuntimeExports.jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxRuntimeExports.jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsxRuntimeExports.jsx(PhoneIcon, {}), location.phone] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxRuntimeExports.jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsxRuntimeExports.jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxRuntimeExports.jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsxRuntimeExports.jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
|
|
44389
44911
|
}
|
|
44390
44912
|
function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
44391
44913
|
const rawState = action.state;
|
|
@@ -44419,40 +44941,443 @@
|
|
|
44419
44941
|
if (isSingleLocation) {
|
|
44420
44942
|
return (jsxRuntimeExports.jsx(LocationItem, { location: locations[0], settings: settings, accentColor: accentColor, onDirections: () => handleDirections(locations[0]), showMap: true }));
|
|
44421
44943
|
}
|
|
44422
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsxRuntimeExports.jsx(MapPinIcon, {}), jsxRuntimeExports.jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsxRuntimeExports.jsx("div", { className:
|
|
44423
|
-
gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
|
|
44424
|
-
}, children: locations.map((location) => (jsxRuntimeExports.jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: settings.showMap !== false, compact: locations.length > 2 }, location.id))) })), layout === 'grid' && (jsxRuntimeExports.jsx("div", { className: "ai-chat-location-card-list__grid", children: locations.map((location) => (jsxRuntimeExports.jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: false, compact: true }, location.id))) })), layout === 'carousel' && (jsxRuntimeExports.jsx("div", { className: "ai-chat-location-card-list__carousel", children: locations.map((location) => (jsxRuntimeExports.jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: true, compact: false }, location.id))) }))] }));
|
|
44944
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsxRuntimeExports.jsx(MapPinIcon, {}), jsxRuntimeExports.jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsxRuntimeExports.jsx("div", { className: `ai-chat-location-card-list__stack ai-chat-location-card-list__stack--cols-${stackColumns}`, children: locations.map((location) => (jsxRuntimeExports.jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: settings.showMap !== false, compact: locations.length > 2 }, location.id))) })), layout === 'grid' && (jsxRuntimeExports.jsx("div", { className: "ai-chat-location-card-list__grid", children: locations.map((location) => (jsxRuntimeExports.jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: false, compact: true }, location.id))) })), layout === 'carousel' && (jsxRuntimeExports.jsx("div", { className: "ai-chat-location-card-list__carousel", children: locations.map((location) => (jsxRuntimeExports.jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: true, compact: false }, location.id))) }))] }));
|
|
44425
44945
|
}
|
|
44426
44946
|
|
|
44427
|
-
|
|
44428
|
-
|
|
44429
|
-
const frontendActionHandlers = {};
|
|
44430
|
-
const actionRenderers = {};
|
|
44431
|
-
function getFrontendActionHandler(implementation) {
|
|
44432
|
-
return frontendActionHandlers[implementation];
|
|
44947
|
+
function UsersIcon() {
|
|
44948
|
+
return (jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), jsxRuntimeExports.jsx("circle", { cx: "9", cy: "7", r: "4" }), jsxRuntimeExports.jsx("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }), jsxRuntimeExports.jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })] }));
|
|
44433
44949
|
}
|
|
44434
|
-
|
|
44435
|
-
|
|
44436
|
-
|
|
44437
|
-
|
|
44438
|
-
|
|
44439
|
-
|
|
44950
|
+
const AVATAR_COLORS = [
|
|
44951
|
+
{ bg: '#E8F5E9', text: '#2E7D32' }, // Green
|
|
44952
|
+
{ bg: '#E3F2FD', text: '#1565C0' }, // Blue
|
|
44953
|
+
{ bg: '#FFF3E0', text: '#E65100' }, // Orange
|
|
44954
|
+
{ bg: '#F3E5F5', text: '#7B1FA2' }, // Purple
|
|
44955
|
+
{ bg: '#FFEBEE', text: '#C62828' }, // Red
|
|
44956
|
+
{ bg: '#E0F7FA', text: '#00838F' }, // Cyan
|
|
44957
|
+
{ bg: '#FFF8E1', text: '#F9A825' }, // Amber
|
|
44958
|
+
{ bg: '#FCE4EC', text: '#AD1457' }, // Pink
|
|
44959
|
+
];
|
|
44960
|
+
function getInitials(name) {
|
|
44961
|
+
const parts = name.trim().split(/\s+/);
|
|
44962
|
+
if (parts.length === 1) {
|
|
44963
|
+
return parts[0].substring(0, 2).toUpperCase();
|
|
44440
44964
|
}
|
|
44441
|
-
return
|
|
44442
|
-
}
|
|
44443
|
-
function waitForActionState(toolCallId) {
|
|
44444
|
-
return new Promise((resolve) => {
|
|
44445
|
-
pendingResolvers.set(toolCallId, resolve);
|
|
44446
|
-
});
|
|
44965
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
44447
44966
|
}
|
|
44448
|
-
function
|
|
44449
|
-
|
|
44450
|
-
|
|
44451
|
-
|
|
44452
|
-
resolver(state);
|
|
44453
|
-
return;
|
|
44967
|
+
function getColorFromName(name) {
|
|
44968
|
+
let hash = 0;
|
|
44969
|
+
for (let i = 0; i < name.length; i++) {
|
|
44970
|
+
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
|
44454
44971
|
}
|
|
44455
|
-
|
|
44972
|
+
return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length];
|
|
44973
|
+
}
|
|
44974
|
+
function ContactItem({ contact, settings, accentColor, onEmail, onPhone, compact = false, layout = 'vertical', }) {
|
|
44975
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
44976
|
+
const layoutClass = layout === 'horizontal'
|
|
44977
|
+
? 'ai-chat-contact-card--horizontal'
|
|
44978
|
+
: 'ai-chat-contact-card--vertical';
|
|
44979
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-action-card ai-chat-contact-card ${layoutClass} ${compact ? 'ai-chat-contact-card--compact' : ''}`, style: style, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card__image-section", children: [contact.profilePictureUrl ? (jsxRuntimeExports.jsx("img", { src: contact.profilePictureUrl, alt: contact.name, className: "ai-chat-contact-card__image", onError: (e) => {
|
|
44980
|
+
e.currentTarget.style.display = 'none';
|
|
44981
|
+
const placeholder = e.currentTarget.parentElement?.querySelector('.ai-chat-contact-card__initials');
|
|
44982
|
+
if (placeholder) {
|
|
44983
|
+
placeholder.style.display = 'flex';
|
|
44984
|
+
}
|
|
44985
|
+
} })) : null, (() => {
|
|
44986
|
+
const colors = getColorFromName(contact.name);
|
|
44987
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-contact-card__initials", style: {
|
|
44988
|
+
display: contact.profilePictureUrl ? 'none' : 'flex',
|
|
44989
|
+
backgroundColor: colors.bg,
|
|
44990
|
+
color: colors.text,
|
|
44991
|
+
}, children: getInitials(contact.name) }));
|
|
44992
|
+
})()] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card__info", children: [jsxRuntimeExports.jsx("h4", { className: "ai-chat-contact-card__name", children: contact.name }), settings.showRole !== false && contact.role && (jsxRuntimeExports.jsx("p", { className: "ai-chat-contact-card__role", children: contact.role })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card__details", children: [settings.showEmail !== false && contact.email && (jsxRuntimeExports.jsx("a", { href: `mailto:${contact.email}`, className: "ai-chat-contact-card__detail", onClick: onEmail, children: contact.email })), settings.showPhone !== false && contact.phone && (jsxRuntimeExports.jsx("a", { href: `tel:${contact.phone}`, className: "ai-chat-contact-card__detail", onClick: onPhone, children: contact.phone }))] }), settings.showResponsibilities !== false && contact.responsibilities && contact.responsibilities.length > 0 && !compact && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card__responsibilities", children: [contact.responsibilities.slice(0, 3).map((resp, idx) => (jsxRuntimeExports.jsx("span", { className: "ai-chat-contact-card__responsibility-tag", children: resp }, idx))), contact.responsibilities.length > 3 && (jsxRuntimeExports.jsxs("span", { className: "ai-chat-contact-card__responsibility-more", children: ["+", contact.responsibilities.length - 3, " more"] }))] }))] })] }));
|
|
44993
|
+
}
|
|
44994
|
+
function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
44995
|
+
const rawState = action.state;
|
|
44996
|
+
const hasCompletedRef = reactExports.useRef(false);
|
|
44997
|
+
const state = {
|
|
44998
|
+
contacts: rawState?.contacts || [],
|
|
44999
|
+
settings: rawState?.settings || {},
|
|
45000
|
+
query: rawState?.query,
|
|
45001
|
+
status: rawState?.status || 'displaying',
|
|
45002
|
+
};
|
|
45003
|
+
const { contacts, settings } = state;
|
|
45004
|
+
const isSingleContact = contacts.length === 1;
|
|
45005
|
+
const stackColumns = Math.min(Math.max(contacts.length, 1), maxColumns);
|
|
45006
|
+
reactExports.useEffect(() => {
|
|
45007
|
+
if (!action.done && !hasCompletedRef.current && onComplete) {
|
|
45008
|
+
hasCompletedRef.current = true;
|
|
45009
|
+
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
45010
|
+
}
|
|
45011
|
+
}, [action.done, action.toolCallId, onComplete, state]);
|
|
45012
|
+
const handleContact = () => {
|
|
45013
|
+
onComplete?.(action.toolCallId, { ...state, status: 'contacted' });
|
|
45014
|
+
};
|
|
45015
|
+
if (contacts.length === 0) {
|
|
45016
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card ai-chat-contact-card--empty", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-contact-card__empty-icon", children: jsxRuntimeExports.jsx(UsersIcon, {}) }), jsxRuntimeExports.jsxs("p", { className: "ai-chat-contact-card__empty-text", children: ["No contacts found", state.query ? ` for "${state.query}"` : ''] })] }));
|
|
45017
|
+
}
|
|
45018
|
+
if (isSingleContact) {
|
|
45019
|
+
return (jsxRuntimeExports.jsx(ContactItem, { contact: contacts[0], settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, layout: settings.layout || 'horizontal' }));
|
|
45020
|
+
}
|
|
45021
|
+
const isWidget = maxColumns === 1;
|
|
45022
|
+
const stackClassName = isWidget
|
|
45023
|
+
? 'ai-chat-contact-card-list__stack ai-chat-contact-card-list__stack--widget'
|
|
45024
|
+
: 'ai-chat-contact-card-list__stack';
|
|
45025
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card-list", style: { containerType: 'inline-size' }, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-contact-card-list__header", children: [jsxRuntimeExports.jsx(UsersIcon, {}), jsxRuntimeExports.jsxs("span", { children: [contacts.length, " Contacts"] })] }), jsxRuntimeExports.jsx("div", { className: stackClassName, style: isWidget ? undefined : {
|
|
45026
|
+
gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
|
|
45027
|
+
}, children: contacts.map((contact) => (jsxRuntimeExports.jsx(ContactItem, { contact: contact, settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, compact: true, layout: settings.layout || 'vertical' }, contact.id))) })] }));
|
|
45028
|
+
}
|
|
45029
|
+
|
|
45030
|
+
function FormCard({ action, onComplete, onDismiss, accentColor }) {
|
|
45031
|
+
const state = action.state;
|
|
45032
|
+
const [currentStep, setCurrentStep] = reactExports.useState(0);
|
|
45033
|
+
const [answers, setAnswers] = reactExports.useState({});
|
|
45034
|
+
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
45035
|
+
const questions = state.questions || [];
|
|
45036
|
+
const currentQuestion = questions[currentStep];
|
|
45037
|
+
const totalQuestions = questions.length;
|
|
45038
|
+
const handleAnswerChange = (questionId, value) => {
|
|
45039
|
+
setAnswers((prev) => ({ ...prev, [questionId]: value }));
|
|
45040
|
+
};
|
|
45041
|
+
const handleNext = () => {
|
|
45042
|
+
if (currentStep < totalQuestions - 1) {
|
|
45043
|
+
setCurrentStep((prev) => prev + 1);
|
|
45044
|
+
}
|
|
45045
|
+
};
|
|
45046
|
+
const handlePrev = () => {
|
|
45047
|
+
if (currentStep > 0) {
|
|
45048
|
+
setCurrentStep((prev) => prev - 1);
|
|
45049
|
+
}
|
|
45050
|
+
};
|
|
45051
|
+
const handleSubmit = () => {
|
|
45052
|
+
if (!onComplete)
|
|
45053
|
+
return;
|
|
45054
|
+
setIsSubmitting(true);
|
|
45055
|
+
const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
|
|
45056
|
+
questionId,
|
|
45057
|
+
value,
|
|
45058
|
+
}));
|
|
45059
|
+
onComplete(action.toolCallId, {
|
|
45060
|
+
...state,
|
|
45061
|
+
status: 'submitted',
|
|
45062
|
+
answers: formattedAnswers,
|
|
45063
|
+
});
|
|
45064
|
+
};
|
|
45065
|
+
const handleSkip = () => {
|
|
45066
|
+
if (!onComplete || !state.settings.allowSkip)
|
|
45067
|
+
return;
|
|
45068
|
+
onComplete(action.toolCallId, {
|
|
45069
|
+
...state,
|
|
45070
|
+
status: 'skipped',
|
|
45071
|
+
});
|
|
45072
|
+
};
|
|
45073
|
+
const isCurrentAnswered = () => {
|
|
45074
|
+
if (!currentQuestion)
|
|
45075
|
+
return false;
|
|
45076
|
+
const answer = answers[currentQuestion.id];
|
|
45077
|
+
if (!answer)
|
|
45078
|
+
return !currentQuestion.required;
|
|
45079
|
+
if (Array.isArray(answer))
|
|
45080
|
+
return answer.length > 0 || !currentQuestion.required;
|
|
45081
|
+
return answer.trim() !== '' || !currentQuestion.required;
|
|
45082
|
+
};
|
|
45083
|
+
const canSubmit = () => {
|
|
45084
|
+
return questions.every((q) => {
|
|
45085
|
+
const answer = answers[q.id];
|
|
45086
|
+
if (!q.required)
|
|
45087
|
+
return true;
|
|
45088
|
+
if (!answer)
|
|
45089
|
+
return false;
|
|
45090
|
+
if (Array.isArray(answer))
|
|
45091
|
+
return answer.length > 0;
|
|
45092
|
+
return answer.trim() !== '';
|
|
45093
|
+
});
|
|
45094
|
+
};
|
|
45095
|
+
const handleDismiss = () => {
|
|
45096
|
+
onDismiss?.(action.toolCallId);
|
|
45097
|
+
};
|
|
45098
|
+
// Error state
|
|
45099
|
+
if (state.status === 'error') {
|
|
45100
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: "\u26A0\uFE0F" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: "Form Error" })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__error", children: state.error || 'Could not load form' })] }));
|
|
45101
|
+
}
|
|
45102
|
+
// Submitted state
|
|
45103
|
+
if (state.status === 'submitted' || action.done) {
|
|
45104
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: "\u2713" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__success", children: state.settings.successMessage || 'Thank you for your response!' })] }));
|
|
45105
|
+
}
|
|
45106
|
+
// Skipped state
|
|
45107
|
+
if (state.status === 'skipped') {
|
|
45108
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: "\u21B7" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
|
|
45109
|
+
}
|
|
45110
|
+
// No questions
|
|
45111
|
+
if (totalQuestions === 0) {
|
|
45112
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__empty-text", children: "This form has no questions." })] }));
|
|
45113
|
+
}
|
|
45114
|
+
const showCloseButton = state.status === "displaying" && !action.done && Boolean(onDismiss);
|
|
45115
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-form-card${showCloseButton ? " ai-chat-form-card--closable" : ""}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__title", children: state.title }), showCloseButton && (jsxRuntimeExports.jsx(CloseButton, { onClick: handleDismiss, ariaLabel: "Close form" }))] }), state.description && (jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__description", children: state.description })), state.context && (jsxRuntimeExports.jsx("p", { className: "ai-chat-form-card__context", children: state.context })), state.settings.showProgress && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__progress", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__progress-bar", style: {
|
|
45116
|
+
width: `${((currentStep + 1) / totalQuestions) * 100}%`,
|
|
45117
|
+
backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
|
|
45118
|
+
} }), jsxRuntimeExports.jsxs("span", { className: "ai-chat-form-card__progress-text", children: [currentStep + 1, " of ", totalQuestions] })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__question", children: [jsxRuntimeExports.jsxs("p", { className: "ai-chat-form-card__question-text", children: [currentQuestion.text, currentQuestion.required && jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__required", children: "*" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__answer", children: [currentQuestion.type === 'text' && (jsxRuntimeExports.jsx("textarea", { className: "ai-chat-form-card__textarea", placeholder: currentQuestion.placeholder || 'Type your answer...', value: answers[currentQuestion.id] || '', onChange: (e) => handleAnswerChange(currentQuestion.id, e.target.value), rows: 3 })), currentQuestion.type === 'single_choice' && currentQuestion.options && (jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => (jsxRuntimeExports.jsxs("label", { className: "ai-chat-form-card__option", children: [jsxRuntimeExports.jsx("input", { type: "radio", name: currentQuestion.id, value: option.value, checked: answers[currentQuestion.id] === option.value, onChange: () => handleAnswerChange(currentQuestion.id, option.value) }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id))) })), currentQuestion.type === 'multiple_choice' && currentQuestion.options && (jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => {
|
|
45119
|
+
const currentAnswers = answers[currentQuestion.id] || [];
|
|
45120
|
+
const isChecked = currentAnswers.includes(option.value);
|
|
45121
|
+
return (jsxRuntimeExports.jsxs("label", { className: "ai-chat-form-card__option", children: [jsxRuntimeExports.jsx("input", { type: "checkbox", value: option.value, checked: isChecked, onChange: () => {
|
|
45122
|
+
const newAnswers = isChecked
|
|
45123
|
+
? currentAnswers.filter((v) => v !== option.value)
|
|
45124
|
+
: [...currentAnswers, option.value];
|
|
45125
|
+
handleAnswerChange(currentQuestion.id, newAnswers);
|
|
45126
|
+
} }), jsxRuntimeExports.jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id));
|
|
45127
|
+
}) })), currentQuestion.type === 'rating' && (jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__rating", children: Array.from({ length: (currentQuestion.maxRating || 5) - (currentQuestion.minRating || 1) + 1 }, (_, i) => (currentQuestion.minRating || 1) + i).map((rating) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-form-card__rating-btn ${answers[currentQuestion.id] === String(rating) ? 'ai-chat-form-card__rating-btn--selected' : ''}`, onClick: () => handleAnswerChange(currentQuestion.id, String(rating)), style: {
|
|
45128
|
+
borderColor: answers[currentQuestion.id] === String(rating)
|
|
45129
|
+
? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
|
|
45130
|
+
: undefined,
|
|
45131
|
+
backgroundColor: answers[currentQuestion.id] === String(rating)
|
|
45132
|
+
? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
|
|
45133
|
+
: undefined,
|
|
45134
|
+
}, children: rating }, rating))) }))] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-form-card__actions", children: [currentStep > 0 && (jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--secondary", onClick: handlePrev, children: "Back" })), state.settings.allowSkip && currentStep === 0 && (jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--ghost", onClick: handleSkip, children: "Skip" })), jsxRuntimeExports.jsx("div", { className: "ai-chat-form-card__actions-spacer" }), currentStep < totalQuestions - 1 ? (jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleNext, disabled: !isCurrentAnswered(), style: {
|
|
45135
|
+
backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
|
|
45136
|
+
}, children: "Next" })) : (jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleSubmit, disabled: !canSubmit() || isSubmitting, style: {
|
|
45137
|
+
backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
|
|
45138
|
+
}, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
|
|
45139
|
+
}
|
|
45140
|
+
|
|
45141
|
+
function Skeleton({ width, height, borderRadius = '4px' }) {
|
|
45142
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
45143
|
+
}
|
|
45144
|
+
function PinInputGroup({ values, onChange, disabled }) {
|
|
45145
|
+
const inputRefs = reactExports.useRef([]);
|
|
45146
|
+
const handleChange = (index, value) => {
|
|
45147
|
+
// Only allow digits
|
|
45148
|
+
const digit = value.replace(/[^0-9]/g, '');
|
|
45149
|
+
const newValues = [...values];
|
|
45150
|
+
newValues[index] = digit.slice(-1);
|
|
45151
|
+
onChange(newValues);
|
|
45152
|
+
// Auto-focus next input
|
|
45153
|
+
if (digit && index < 5) {
|
|
45154
|
+
inputRefs.current[index + 1]?.focus();
|
|
45155
|
+
}
|
|
45156
|
+
};
|
|
45157
|
+
const handleKeyDown = (index, e) => {
|
|
45158
|
+
if (e.key === 'Backspace' && !values[index] && index > 0) {
|
|
45159
|
+
inputRefs.current[index - 1]?.focus();
|
|
45160
|
+
}
|
|
45161
|
+
};
|
|
45162
|
+
const handlePaste = (e) => {
|
|
45163
|
+
e.preventDefault();
|
|
45164
|
+
const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
|
|
45165
|
+
const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
|
|
45166
|
+
onChange(newValues);
|
|
45167
|
+
// Focus the next empty input or the last one
|
|
45168
|
+
const nextIndex = Math.min(pastedData.length, 5);
|
|
45169
|
+
inputRefs.current[nextIndex]?.focus();
|
|
45170
|
+
};
|
|
45171
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsxRuntimeExports.jsx("input", { ref: (el) => {
|
|
45172
|
+
inputRefs.current[index] = el;
|
|
45173
|
+
}, type: "text", inputMode: "numeric", maxLength: 1, className: "ai-chat-pin-input", value: value, onChange: (e) => handleChange(index, e.target.value), onKeyDown: (e) => handleKeyDown(index, e), onPaste: handlePaste, disabled: disabled, autoFocus: index === 0 }, index))) }));
|
|
45174
|
+
}
|
|
45175
|
+
function BookContactAppointmentCard({ action, onComplete, accentColor }) {
|
|
45176
|
+
const state = action.state;
|
|
45177
|
+
const [emailInput, setEmailInput] = reactExports.useState('');
|
|
45178
|
+
const [otpValues, setOtpValues] = reactExports.useState(Array(6).fill(''));
|
|
45179
|
+
const [subjectInput, setSubjectInput] = reactExports.useState(state.subject || '');
|
|
45180
|
+
const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
|
|
45181
|
+
const [emailError, setEmailError] = reactExports.useState(null);
|
|
45182
|
+
const [otpError, setOtpError] = reactExports.useState(null);
|
|
45183
|
+
const phase = state.phase || 'awaiting_email';
|
|
45184
|
+
const handleSubmit = (newState, delay = 50) => {
|
|
45185
|
+
if (!onComplete)
|
|
45186
|
+
return;
|
|
45187
|
+
setIsSubmitting(true);
|
|
45188
|
+
setTimeout(() => {
|
|
45189
|
+
onComplete(action.toolCallId, { ...state, ...newState, errorMessage: null });
|
|
45190
|
+
}, delay);
|
|
45191
|
+
};
|
|
45192
|
+
reactExports.useEffect(() => {
|
|
45193
|
+
setIsSubmitting(false);
|
|
45194
|
+
if (phase === 'awaiting_email') {
|
|
45195
|
+
setEmailError(null);
|
|
45196
|
+
setOtpError(null);
|
|
45197
|
+
}
|
|
45198
|
+
else if (phase === 'awaiting_otp') {
|
|
45199
|
+
setOtpError(state.errorMessage || null);
|
|
45200
|
+
setEmailError(null);
|
|
45201
|
+
setOtpValues(Array(6).fill(''));
|
|
45202
|
+
if (state.email) {
|
|
45203
|
+
setEmailInput(state.email);
|
|
45204
|
+
}
|
|
45205
|
+
}
|
|
45206
|
+
else {
|
|
45207
|
+
setEmailError(null);
|
|
45208
|
+
setOtpError(null);
|
|
45209
|
+
}
|
|
45210
|
+
}, [phase, state.errorMessage]);
|
|
45211
|
+
const isWaitingForBackend = !action.done && Boolean(state.confirmed) && phase === 'awaiting_confirmation';
|
|
45212
|
+
const renderSkeleton = () => (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsxRuntimeExports.jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsxRuntimeExports.jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsxRuntimeExports.jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsxRuntimeExports.jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxRuntimeExports.jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
45213
|
+
const handleEmailSubmit = () => {
|
|
45214
|
+
const trimmedEmail = emailInput.trim();
|
|
45215
|
+
if (!trimmedEmail) {
|
|
45216
|
+
setEmailError('Please enter your email address');
|
|
45217
|
+
return;
|
|
45218
|
+
}
|
|
45219
|
+
setEmailError(null);
|
|
45220
|
+
setEmailInput(trimmedEmail);
|
|
45221
|
+
handleSubmit({ email: trimmedEmail });
|
|
45222
|
+
};
|
|
45223
|
+
const handleOtpSubmit = () => {
|
|
45224
|
+
const code = otpValues.join('');
|
|
45225
|
+
if (code.length !== 6) {
|
|
45226
|
+
setOtpError('Please enter the 6-digit code');
|
|
45227
|
+
return;
|
|
45228
|
+
}
|
|
45229
|
+
setOtpError(null);
|
|
45230
|
+
const resolvedEmail = state.email || emailInput.trim() || null;
|
|
45231
|
+
handleSubmit({ otpCode: code, email: resolvedEmail });
|
|
45232
|
+
};
|
|
45233
|
+
// ========================================
|
|
45234
|
+
// Terminal States
|
|
45235
|
+
// ========================================
|
|
45236
|
+
if (phase === 'booked') {
|
|
45237
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--success", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2713" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Booked" })] }), state.bookedTeamsLink && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__success-text", children: "Your appointment has been confirmed. You can join via Microsoft Teams." }), jsxRuntimeExports.jsx("a", { href: state.bookedTeamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__link", style: { color: accentColor }, children: "Join Teams Meeting \u2192" })] }))] }));
|
|
45238
|
+
}
|
|
45239
|
+
if (phase === 'pending_approval') {
|
|
45240
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--pending", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u23F3" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Awaiting Approval" })] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__content", children: jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__pending-text", children: "Your appointment request has been sent and is awaiting approval from the contact." }) })] }));
|
|
45241
|
+
}
|
|
45242
|
+
if (phase === 'cancelled') {
|
|
45243
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card ai-chat-booking-card--cancelled", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2715" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Appointment Cancelled" })] }) }));
|
|
45244
|
+
}
|
|
45245
|
+
if (phase === 'error') {
|
|
45246
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card ai-chat-booking-card--error", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u26A0\uFE0F" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking Error" })] }), state.errorMessage && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage }))] }));
|
|
45247
|
+
}
|
|
45248
|
+
if (isSubmitting || isWaitingForBackend) {
|
|
45249
|
+
return renderSkeleton();
|
|
45250
|
+
}
|
|
45251
|
+
// ========================================
|
|
45252
|
+
// Phase: Email Collection
|
|
45253
|
+
// ========================================
|
|
45254
|
+
if (phase === 'awaiting_email') {
|
|
45255
|
+
const displayError = emailError || state.errorMessage;
|
|
45256
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCE7" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Enter Your Email" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__description", children: "Please enter your email address to start the booking process." }), displayError && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntimeExports.jsx("input", { type: "email", className: "ai-chat-booking-card__input", placeholder: "your@email.com", value: emailInput, onChange: (e) => {
|
|
45257
|
+
setEmailInput(e.target.value);
|
|
45258
|
+
setEmailError(null);
|
|
45259
|
+
}, onKeyDown: (e) => {
|
|
45260
|
+
if (e.key === 'Enter') {
|
|
45261
|
+
handleEmailSubmit();
|
|
45262
|
+
}
|
|
45263
|
+
} }), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleEmailSubmit, disabled: !emailInput.trim(), style: {
|
|
45264
|
+
backgroundColor: accentColor || undefined,
|
|
45265
|
+
borderColor: accentColor || undefined,
|
|
45266
|
+
}, children: "Continue" })] })] }));
|
|
45267
|
+
}
|
|
45268
|
+
// ========================================
|
|
45269
|
+
// Phase: OTP Verification
|
|
45270
|
+
// ========================================
|
|
45271
|
+
if (phase === 'awaiting_otp') {
|
|
45272
|
+
const displayError = otpError || state.errorMessage;
|
|
45273
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDD10" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Verify Your Email" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Enter the verification code sent to ", jsxRuntimeExports.jsx("strong", { children: state.email })] }), jsxRuntimeExports.jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
|
|
45274
|
+
setOtpValues(newValues);
|
|
45275
|
+
setOtpError(null);
|
|
45276
|
+
if (newValues.every((value) => value.length === 1) && !isSubmitting) {
|
|
45277
|
+
const resolvedEmail = state.email || emailInput.trim() || null;
|
|
45278
|
+
handleSubmit({ otpCode: newValues.join(''), email: resolvedEmail }, 100);
|
|
45279
|
+
}
|
|
45280
|
+
}, disabled: isSubmitting }), displayError && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: displayError })), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, style: {
|
|
45281
|
+
backgroundColor: accentColor || undefined,
|
|
45282
|
+
borderColor: accentColor || undefined,
|
|
45283
|
+
}, children: "Verify" })] })] }));
|
|
45284
|
+
}
|
|
45285
|
+
// ========================================
|
|
45286
|
+
// Phase: Contact Selection
|
|
45287
|
+
// ========================================
|
|
45288
|
+
if (phase === 'awaiting_contact_selection') {
|
|
45289
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDC65" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Select a Contact" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), state.bookableContacts.length === 0 ? (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__empty", children: "No contacts available for booking." })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__grid", children: state.bookableContacts.map((contact) => (jsxRuntimeExports.jsxs("button", { className: `ai-chat-booking-card__contact ${state.selectedContactId === contact.id ? 'ai-chat-booking-card__contact--selected' : ''}`, onClick: () => handleSubmit({ selectedContactId: contact.id }), style: {
|
|
45290
|
+
borderColor: state.selectedContactId === contact.id
|
|
45291
|
+
? accentColor || undefined
|
|
45292
|
+
: undefined,
|
|
45293
|
+
backgroundColor: state.selectedContactId === contact.id
|
|
45294
|
+
? `${accentColor || '#3b82f6'}15`
|
|
45295
|
+
: undefined,
|
|
45296
|
+
}, children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__contact-name", children: contact.name }), contact.role && (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__contact-role", children: contact.role }))] }, contact.id))) }))] })] }));
|
|
45297
|
+
}
|
|
45298
|
+
// ========================================
|
|
45299
|
+
// Phase: Options Selection
|
|
45300
|
+
// ========================================
|
|
45301
|
+
if (phase === 'awaiting_options') {
|
|
45302
|
+
const selectedContact = state.bookableContacts.find((c) => c.id === state.selectedContactId);
|
|
45303
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCC5" }), jsxRuntimeExports.jsxs("span", { className: "ai-chat-booking-card__title", children: ["Book with ", selectedContact?.name] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__options", children: [jsxRuntimeExports.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'book_new' }), children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\u2795" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-text", children: "Book New Appointment" })] }), state.userAppointments.length > 0 && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'view_existing' }), children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\uD83D\uDCCB" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-text", children: "View Appointments" })] }), jsxRuntimeExports.jsxs("button", { className: "ai-chat-booking-card__option-btn", onClick: () => handleSubmit({ selectedOption: 'cancel_existing' }), children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-icon", children: "\u2715" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__option-text", children: "Cancel Appointment" })] })] }))] })] })] }));
|
|
45304
|
+
}
|
|
45305
|
+
// ========================================
|
|
45306
|
+
// Phase: View Existing Appointments
|
|
45307
|
+
// ========================================
|
|
45308
|
+
if (state.phase === 'awaiting_options' && state.selectedOption === 'view_existing') {
|
|
45309
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCCB" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Your Appointments" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.userAppointments.length === 0 ? (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__empty", children: "You have no appointments yet." })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__appointments", children: state.userAppointments.map((apt) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__appointment-header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }), jsxRuntimeExports.jsx("span", { className: `ai-chat-booking-card__appointment-status ai-chat-booking-card__appointment-status--${apt.status}`, children: apt.status })] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__appointment-contact", children: ["with ", apt.contactName] }), apt.teamsLink && (jsxRuntimeExports.jsx("a", { href: apt.teamsLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-booking-card__link", style: { color: accentColor }, children: "Join Teams Meeting \u2192" }))] }, apt.id))) })), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: () => handleSubmit({ selectedOption: undefined }), children: "Back" })] })] }));
|
|
45310
|
+
}
|
|
45311
|
+
// ========================================
|
|
45312
|
+
// Phase: Cancel Appointment
|
|
45313
|
+
// ========================================
|
|
45314
|
+
if (state.phase === 'awaiting_options' && state.selectedOption === 'cancel_existing') {
|
|
45315
|
+
const activeAppointments = state.userAppointments.filter((a) => a.status !== 'cancelled' && a.status !== 'declined');
|
|
45316
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2715" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Cancel Appointment" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), activeAppointments.length === 0 ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__empty", children: "No active appointments to cancel." }), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--secondary", onClick: () => handleSubmit({ selectedOption: undefined }), children: "Back" })] })) : (jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__appointments", children: activeAppointments.map((apt) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__appointment", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__appointment-header", children: jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__appointment-subject", children: apt.subject }) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__appointment-time", children: apt.displayTime }), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--danger", onClick: () => handleSubmit({ selectedAppointmentId: apt.id, confirmCancel: true }), children: "Cancel This Appointment" })] }, apt.id))) }))] })] }));
|
|
45317
|
+
}
|
|
45318
|
+
// ========================================
|
|
45319
|
+
// Phase: Slot Selection
|
|
45320
|
+
// ========================================
|
|
45321
|
+
if (phase === 'awaiting_slot_selection') {
|
|
45322
|
+
const groupedSlots = state.availableSlots.reduce((acc, slot) => {
|
|
45323
|
+
if (!acc[slot.displayDate]) {
|
|
45324
|
+
acc[slot.displayDate] = [];
|
|
45325
|
+
}
|
|
45326
|
+
acc[slot.displayDate].push(slot);
|
|
45327
|
+
return acc;
|
|
45328
|
+
}, {});
|
|
45329
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDD50" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Select a Time Slot" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [jsxRuntimeExports.jsxs("p", { className: "ai-chat-booking-card__description", children: ["Available times in ", state.timeZone] }), state.errorMessage && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), Object.entries(groupedSlots).map(([date, slots]) => (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__date-group", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__date-header", children: date }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__slots", children: slots.map((slot, idx) => {
|
|
45330
|
+
const isSelected = state.selectedSlot?.startTime === slot.startTime &&
|
|
45331
|
+
state.selectedSlot?.endTime === slot.endTime;
|
|
45332
|
+
return (jsxRuntimeExports.jsx("button", { className: `ai-chat-booking-card__slot ${isSelected ? 'ai-chat-booking-card__slot--selected' : ''}`, onClick: () => handleSubmit({
|
|
45333
|
+
selectedSlot: { startTime: slot.startTime, endTime: slot.endTime },
|
|
45334
|
+
}), style: {
|
|
45335
|
+
borderColor: isSelected ? accentColor || undefined : undefined,
|
|
45336
|
+
backgroundColor: isSelected ? `${accentColor || '#3b82f6'}15` : undefined,
|
|
45337
|
+
}, children: slot.displayTime }, `${slot.startTime}-${idx}`));
|
|
45338
|
+
}) })] }, date))), state.availableSlots.length === 0 && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__empty", children: "No available time slots." }))] })] }));
|
|
45339
|
+
}
|
|
45340
|
+
// ========================================
|
|
45341
|
+
// Phase: Confirmation
|
|
45342
|
+
// ========================================
|
|
45343
|
+
if (phase === 'awaiting_confirmation') {
|
|
45344
|
+
const selectedContact = state.bookableContacts.find((c) => c.id === state.selectedContactId);
|
|
45345
|
+
const selectedSlot = state.availableSlots.find((s) => s.startTime === state.selectedSlot?.startTime && s.endTime === state.selectedSlot?.endTime);
|
|
45346
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\u2713" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Confirm Booking" })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__content", children: [state.errorMessage && (jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__error", children: state.errorMessage })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Contact:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedContact?.name })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Date:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedSlot?.displayDate })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__summary-row", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-label", children: "Time:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__summary-value", children: selectedSlot?.displayTime })] })] }), state.allowCustomSubject && (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-booking-card__label", children: "Subject (optional):" }), jsxRuntimeExports.jsx("input", { type: "text", className: "ai-chat-booking-card__input", placeholder: "Meeting subject", value: subjectInput, onChange: (e) => setSubjectInput(e.target.value) })] })), jsxRuntimeExports.jsx("button", { className: "ai-chat-booking-card__btn ai-chat-booking-card__btn--primary", onClick: () => handleSubmit({
|
|
45347
|
+
subject: state.allowCustomSubject ? subjectInput || undefined : undefined,
|
|
45348
|
+
confirmed: true,
|
|
45349
|
+
}), style: {
|
|
45350
|
+
backgroundColor: accentColor || undefined,
|
|
45351
|
+
borderColor: accentColor || undefined,
|
|
45352
|
+
}, children: "Confirm Booking" })] })] }));
|
|
45353
|
+
}
|
|
45354
|
+
// Fallback for unknown states
|
|
45355
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-booking-card__header", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__icon", children: "\uD83D\uDCC5" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-booking-card__title", children: "Booking" })] }), jsxRuntimeExports.jsx("div", { className: "ai-chat-booking-card__content", children: jsxRuntimeExports.jsx("p", { className: "ai-chat-booking-card__description", children: "Loading booking options..." }) })] }));
|
|
45356
|
+
}
|
|
45357
|
+
|
|
45358
|
+
const pendingResolvers = new Map();
|
|
45359
|
+
const resumeCallbacks = new Map();
|
|
45360
|
+
const frontendActionHandlers = {};
|
|
45361
|
+
const actionRenderers = {};
|
|
45362
|
+
function getFrontendActionHandler(implementation) {
|
|
45363
|
+
return frontendActionHandlers[implementation];
|
|
45364
|
+
}
|
|
45365
|
+
function getActionRenderer(implementation) {
|
|
45366
|
+
return actionRenderers[implementation];
|
|
45367
|
+
}
|
|
45368
|
+
function waitForActionState(toolCallId) {
|
|
45369
|
+
return new Promise((resolve) => {
|
|
45370
|
+
pendingResolvers.set(toolCallId, resolve);
|
|
45371
|
+
});
|
|
45372
|
+
}
|
|
45373
|
+
function resolveActionState(toolCallId, state) {
|
|
45374
|
+
const resolver = pendingResolvers.get(toolCallId);
|
|
45375
|
+
if (resolver) {
|
|
45376
|
+
pendingResolvers.delete(toolCallId);
|
|
45377
|
+
resolver(state);
|
|
45378
|
+
return;
|
|
45379
|
+
}
|
|
45380
|
+
const resumeCallback = resumeCallbacks.get(toolCallId);
|
|
44456
45381
|
if (resumeCallback) {
|
|
44457
45382
|
resumeCallback(state).catch((error) => {
|
|
44458
45383
|
console.error("[Action] Failed to resume action:", error);
|
|
@@ -44480,13 +45405,19 @@
|
|
|
44480
45405
|
// Register the handler
|
|
44481
45406
|
registerGoogleCalendarHandler();
|
|
44482
45407
|
// Register the renderer
|
|
44483
|
-
actionRenderers["google-calendar-appointment"] = (message) => {
|
|
45408
|
+
actionRenderers["google-calendar-appointment"] = (message, accentColor, _variant, onActionDismiss) => {
|
|
44484
45409
|
const action = message.action;
|
|
44485
45410
|
if (!action)
|
|
44486
45411
|
return null;
|
|
44487
45412
|
const handleComplete = (toolCallId, newState) => {
|
|
44488
45413
|
resolveActionState(toolCallId, newState);
|
|
44489
45414
|
};
|
|
45415
|
+
const handleDismiss = onActionDismiss
|
|
45416
|
+
? (toolCallId) => {
|
|
45417
|
+
resolveActionState(toolCallId, { __dismissed: true });
|
|
45418
|
+
onActionDismiss(toolCallId);
|
|
45419
|
+
}
|
|
45420
|
+
: undefined;
|
|
44490
45421
|
return (jsxRuntimeExports.jsx(GoogleCalendarCard, { action: {
|
|
44491
45422
|
implementation: action.implementation,
|
|
44492
45423
|
toolCallId: action.toolCallId,
|
|
@@ -44494,7 +45425,45 @@
|
|
|
44494
45425
|
input: action.input,
|
|
44495
45426
|
state: action.state,
|
|
44496
45427
|
done: action.done ?? false,
|
|
44497
|
-
}, onComplete: handleComplete }));
|
|
45428
|
+
}, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
|
|
45429
|
+
};
|
|
45430
|
+
}
|
|
45431
|
+
|
|
45432
|
+
function registerMicrosoftCalendarHandler() {
|
|
45433
|
+
frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
|
|
45434
|
+
return waitForActionState(context.toolCallId);
|
|
45435
|
+
};
|
|
45436
|
+
}
|
|
45437
|
+
|
|
45438
|
+
/**
|
|
45439
|
+
* Register microsoft-calendar-appointment action handler and renderer.
|
|
45440
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
45441
|
+
*/
|
|
45442
|
+
function registerMicrosoftCalendarAction() {
|
|
45443
|
+
// Register the handler
|
|
45444
|
+
registerMicrosoftCalendarHandler();
|
|
45445
|
+
// Register the renderer
|
|
45446
|
+
actionRenderers["microsoft-calendar-appointment"] = (message, accentColor, _variant, onActionDismiss) => {
|
|
45447
|
+
const action = message.action;
|
|
45448
|
+
if (!action)
|
|
45449
|
+
return null;
|
|
45450
|
+
const handleComplete = (toolCallId, newState) => {
|
|
45451
|
+
resolveActionState(toolCallId, newState);
|
|
45452
|
+
};
|
|
45453
|
+
const handleDismiss = onActionDismiss
|
|
45454
|
+
? (toolCallId) => {
|
|
45455
|
+
resolveActionState(toolCallId, { __dismissed: true });
|
|
45456
|
+
onActionDismiss(toolCallId);
|
|
45457
|
+
}
|
|
45458
|
+
: undefined;
|
|
45459
|
+
return (jsxRuntimeExports.jsx(MicrosoftCalendarCard, { action: {
|
|
45460
|
+
implementation: action.implementation,
|
|
45461
|
+
toolCallId: action.toolCallId,
|
|
45462
|
+
actionId: action.actionId,
|
|
45463
|
+
input: action.input,
|
|
45464
|
+
state: action.state,
|
|
45465
|
+
done: action.done ?? false,
|
|
45466
|
+
}, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
|
|
44498
45467
|
};
|
|
44499
45468
|
}
|
|
44500
45469
|
|
|
@@ -44508,7 +45477,7 @@
|
|
|
44508
45477
|
return { ...state, status: "displaying" };
|
|
44509
45478
|
};
|
|
44510
45479
|
// Renderer - displays the link preview card
|
|
44511
|
-
actionRenderers["link-preview"] = (message) => {
|
|
45480
|
+
actionRenderers["link-preview"] = (message, accentColor) => {
|
|
44512
45481
|
const action = message.action;
|
|
44513
45482
|
if (!action)
|
|
44514
45483
|
return null;
|
|
@@ -44526,7 +45495,7 @@
|
|
|
44526
45495
|
input: action.input,
|
|
44527
45496
|
state: action.state,
|
|
44528
45497
|
done: isDone,
|
|
44529
|
-
}, onComplete: handleComplete }));
|
|
45498
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
44530
45499
|
};
|
|
44531
45500
|
}
|
|
44532
45501
|
|
|
@@ -44540,7 +45509,7 @@
|
|
|
44540
45509
|
return { ...state, status: "displaying" };
|
|
44541
45510
|
};
|
|
44542
45511
|
// Renderer - displays the embedded video player card
|
|
44543
|
-
actionRenderers["video-player"] = (message) => {
|
|
45512
|
+
actionRenderers["video-player"] = (message, accentColor) => {
|
|
44544
45513
|
const action = message.action;
|
|
44545
45514
|
if (!action)
|
|
44546
45515
|
return null;
|
|
@@ -44558,7 +45527,7 @@
|
|
|
44558
45527
|
input: action.input,
|
|
44559
45528
|
state: action.state,
|
|
44560
45529
|
done: isDone,
|
|
44561
|
-
}, onComplete: handleComplete }));
|
|
45530
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
44562
45531
|
};
|
|
44563
45532
|
}
|
|
44564
45533
|
|
|
@@ -44572,7 +45541,7 @@
|
|
|
44572
45541
|
return { ...state, status: "displaying" };
|
|
44573
45542
|
};
|
|
44574
45543
|
// Renderer - displays the location card
|
|
44575
|
-
actionRenderers["location-card"] = (message, accentColor) => {
|
|
45544
|
+
actionRenderers["location-card"] = (message, accentColor, variant) => {
|
|
44576
45545
|
const action = message.action;
|
|
44577
45546
|
if (!action)
|
|
44578
45547
|
return null;
|
|
@@ -44590,7 +45559,134 @@
|
|
|
44590
45559
|
input: action.input,
|
|
44591
45560
|
state: action.state,
|
|
44592
45561
|
done: isDone,
|
|
44593
|
-
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: 1 }));
|
|
45562
|
+
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
45563
|
+
};
|
|
45564
|
+
}
|
|
45565
|
+
|
|
45566
|
+
function registerContactCardAction() {
|
|
45567
|
+
// Handler - auto-completes immediately since no user input is needed
|
|
45568
|
+
frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
|
|
45569
|
+
return { ...state, status: 'displaying' };
|
|
45570
|
+
};
|
|
45571
|
+
// Renderer - displays the contact card
|
|
45572
|
+
actionRenderers['contact-card'] = (message, accentColor, variant) => {
|
|
45573
|
+
const action = message.action;
|
|
45574
|
+
if (!action)
|
|
45575
|
+
return null;
|
|
45576
|
+
const handleComplete = (toolCallId, newState) => {
|
|
45577
|
+
resolveActionState(toolCallId, newState);
|
|
45578
|
+
};
|
|
45579
|
+
// Check if action state indicates it's already complete
|
|
45580
|
+
const state = action.state;
|
|
45581
|
+
const status = state?.status;
|
|
45582
|
+
const isDone = action.done || status === 'displaying' || status === 'contacted';
|
|
45583
|
+
return (jsxRuntimeExports.jsx(ContactCard, { action: {
|
|
45584
|
+
implementation: action.implementation,
|
|
45585
|
+
toolCallId: action.toolCallId,
|
|
45586
|
+
actionId: action.actionId,
|
|
45587
|
+
input: action.input,
|
|
45588
|
+
state: action.state,
|
|
45589
|
+
done: isDone,
|
|
45590
|
+
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
45591
|
+
};
|
|
45592
|
+
}
|
|
45593
|
+
|
|
45594
|
+
function registerQueryContactDirectoryAction() {
|
|
45595
|
+
// Handler - auto-completes immediately since no user input is needed
|
|
45596
|
+
frontendActionHandlers['query-contact-directory'] = async (_input, state, _context) => {
|
|
45597
|
+
return { ...state, status: 'displaying' };
|
|
45598
|
+
};
|
|
45599
|
+
// Renderer - displays the contact card with search results
|
|
45600
|
+
actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
|
|
45601
|
+
const action = message.action;
|
|
45602
|
+
if (!action)
|
|
45603
|
+
return null;
|
|
45604
|
+
// Handle completion - triggers agent to continue with text response
|
|
45605
|
+
const handleComplete = (toolCallId, newState) => {
|
|
45606
|
+
resolveActionState(toolCallId, newState);
|
|
45607
|
+
};
|
|
45608
|
+
// Check if action state indicates it's already complete
|
|
45609
|
+
const state = action.state;
|
|
45610
|
+
const status = state?.status;
|
|
45611
|
+
const isDone = action.done || status === 'displaying' || status === 'contacted';
|
|
45612
|
+
return (jsxRuntimeExports.jsx(ContactCard, { action: {
|
|
45613
|
+
implementation: action.implementation,
|
|
45614
|
+
toolCallId: action.toolCallId,
|
|
45615
|
+
actionId: action.actionId,
|
|
45616
|
+
input: action.input,
|
|
45617
|
+
state: action.state,
|
|
45618
|
+
done: isDone,
|
|
45619
|
+
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
45620
|
+
};
|
|
45621
|
+
}
|
|
45622
|
+
|
|
45623
|
+
function registerDisplayFormAction() {
|
|
45624
|
+
// Handler - handles form submission and state updates
|
|
45625
|
+
frontendActionHandlers['display-form'] = async (_input, _state, context) => {
|
|
45626
|
+
return waitForActionState(context.toolCallId);
|
|
45627
|
+
};
|
|
45628
|
+
// Renderer - displays the form card
|
|
45629
|
+
actionRenderers['display-form'] = (message, accentColor, variant, onActionDismiss) => {
|
|
45630
|
+
const action = message.action;
|
|
45631
|
+
if (!action)
|
|
45632
|
+
return null;
|
|
45633
|
+
const handleComplete = (toolCallId, newState) => {
|
|
45634
|
+
resolveActionState(toolCallId, newState);
|
|
45635
|
+
};
|
|
45636
|
+
const handleDismiss = onActionDismiss
|
|
45637
|
+
? (toolCallId) => {
|
|
45638
|
+
resolveActionState(toolCallId, { __dismissed: true });
|
|
45639
|
+
onActionDismiss(toolCallId);
|
|
45640
|
+
}
|
|
45641
|
+
: undefined;
|
|
45642
|
+
// Check if action state indicates it's already complete
|
|
45643
|
+
const state = action.state;
|
|
45644
|
+
const status = state?.status;
|
|
45645
|
+
const isDone = action.done || status === 'completed' || status === 'submitted';
|
|
45646
|
+
return (jsxRuntimeExports.jsx(FormCard, { action: {
|
|
45647
|
+
implementation: action.implementation,
|
|
45648
|
+
toolCallId: action.toolCallId,
|
|
45649
|
+
actionId: action.actionId,
|
|
45650
|
+
input: action.input,
|
|
45651
|
+
state: action.state,
|
|
45652
|
+
done: isDone,
|
|
45653
|
+
}, onComplete: handleComplete, onDismiss: handleDismiss, accentColor: accentColor }));
|
|
45654
|
+
};
|
|
45655
|
+
}
|
|
45656
|
+
|
|
45657
|
+
/**
|
|
45658
|
+
* Book Contact Appointment Handler
|
|
45659
|
+
* Frontend action handler that waits for action completion
|
|
45660
|
+
*/
|
|
45661
|
+
function registerBookContactAppointmentHandler() {
|
|
45662
|
+
frontendActionHandlers["book-contact-appointment"] = async (_input, _state, context) => {
|
|
45663
|
+
return waitForActionState(context.toolCallId);
|
|
45664
|
+
};
|
|
45665
|
+
}
|
|
45666
|
+
|
|
45667
|
+
/**
|
|
45668
|
+
* Register book-contact-appointment action handler and renderer.
|
|
45669
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
45670
|
+
*/
|
|
45671
|
+
function registerBookContactAppointmentAction() {
|
|
45672
|
+
// Register the handler
|
|
45673
|
+
registerBookContactAppointmentHandler();
|
|
45674
|
+
// Register the renderer
|
|
45675
|
+
actionRenderers['book-contact-appointment'] = (message, accentColor) => {
|
|
45676
|
+
const action = message.action;
|
|
45677
|
+
if (!action)
|
|
45678
|
+
return null;
|
|
45679
|
+
const handleComplete = (toolCallId, newState) => {
|
|
45680
|
+
resolveActionState(toolCallId, newState);
|
|
45681
|
+
};
|
|
45682
|
+
return (jsxRuntimeExports.jsx(BookContactAppointmentCard, { action: {
|
|
45683
|
+
implementation: action.implementation,
|
|
45684
|
+
toolCallId: action.toolCallId,
|
|
45685
|
+
actionId: action.actionId,
|
|
45686
|
+
input: action.input,
|
|
45687
|
+
state: action.state,
|
|
45688
|
+
done: action.done ?? false,
|
|
45689
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
44594
45690
|
};
|
|
44595
45691
|
}
|
|
44596
45692
|
|
|
@@ -44607,9 +45703,14 @@
|
|
|
44607
45703
|
initialized = true;
|
|
44608
45704
|
// Explicitly call each registration function to prevent tree-shaking
|
|
44609
45705
|
registerGoogleCalendarAction();
|
|
45706
|
+
registerMicrosoftCalendarAction();
|
|
44610
45707
|
registerLinkPreviewAction();
|
|
44611
45708
|
registerVideoPlayerAction();
|
|
44612
45709
|
registerLocationCardAction();
|
|
45710
|
+
registerQueryContactDirectoryAction();
|
|
45711
|
+
registerContactCardAction();
|
|
45712
|
+
registerDisplayFormAction();
|
|
45713
|
+
registerBookContactAppointmentAction();
|
|
44613
45714
|
}
|
|
44614
45715
|
|
|
44615
45716
|
/**
|
|
@@ -44829,12 +45930,6 @@
|
|
|
44829
45930
|
}
|
|
44830
45931
|
}
|
|
44831
45932
|
|
|
44832
|
-
/**
|
|
44833
|
-
* useChat Hook
|
|
44834
|
-
* Main state management for chat functionality
|
|
44835
|
-
*/
|
|
44836
|
-
// Initialize action handlers immediately to prevent tree-shaking
|
|
44837
|
-
initializeActionHandlers();
|
|
44838
45933
|
function hydrateToolNames(messages) {
|
|
44839
45934
|
const toolCallNameById = new Map();
|
|
44840
45935
|
for (const entry of messages) {
|
|
@@ -44878,118 +45973,78 @@
|
|
|
44878
45973
|
};
|
|
44879
45974
|
});
|
|
44880
45975
|
}
|
|
44881
|
-
function
|
|
44882
|
-
|
|
44883
|
-
|
|
44884
|
-
return entry;
|
|
44885
|
-
}
|
|
44886
|
-
const content = typeof entry.message.content === "string" ? entry.message.content : "";
|
|
44887
|
-
if (content.trim().length > 0) {
|
|
44888
|
-
return entry;
|
|
44889
|
-
}
|
|
44890
|
-
return {
|
|
44891
|
-
...entry,
|
|
44892
|
-
message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
|
|
44893
|
-
};
|
|
44894
|
-
});
|
|
45976
|
+
function hydrateMessages(messages) {
|
|
45977
|
+
const visibleMessages = messages.filter((message) => !message.action?.hidden);
|
|
45978
|
+
return hydrateToolNames(visibleMessages);
|
|
44895
45979
|
}
|
|
44896
|
-
|
|
44897
|
-
|
|
44898
|
-
|
|
44899
|
-
|
|
44900
|
-
|
|
44901
|
-
|
|
44902
|
-
|
|
44903
|
-
|
|
45980
|
+
|
|
45981
|
+
function deriveErrorInfo(error) {
|
|
45982
|
+
if (error instanceof ApiError) {
|
|
45983
|
+
const retryAfterSeconds = typeof error.retryAfterMs === 'number'
|
|
45984
|
+
? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
|
|
45985
|
+
: undefined;
|
|
45986
|
+
const lowerMessage = (error.message || '').toLowerCase();
|
|
45987
|
+
let message;
|
|
45988
|
+
switch (error.status) {
|
|
45989
|
+
case 429: {
|
|
45990
|
+
const isPerUser = lowerMessage.includes('user');
|
|
45991
|
+
const base = isPerUser
|
|
45992
|
+
? 'You have reached the per-user rate limit.'
|
|
45993
|
+
: 'This widget has received too many requests.';
|
|
45994
|
+
if (retryAfterSeconds) {
|
|
45995
|
+
message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
|
|
45996
|
+
}
|
|
45997
|
+
else {
|
|
45998
|
+
message = `${base} Please wait a moment and try again.`;
|
|
45999
|
+
}
|
|
46000
|
+
break;
|
|
46001
|
+
}
|
|
46002
|
+
case 401:
|
|
46003
|
+
message = 'Authentication failed. Please refresh the page or verify your API key.';
|
|
46004
|
+
break;
|
|
46005
|
+
case 403:
|
|
46006
|
+
message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
|
|
46007
|
+
break;
|
|
46008
|
+
case 404:
|
|
46009
|
+
if (lowerMessage.includes('not active')) {
|
|
46010
|
+
message = 'This widget is currently inactive. Please contact the site owner.';
|
|
46011
|
+
}
|
|
46012
|
+
else {
|
|
46013
|
+
message = 'We could not find this widget. It may have been removed.';
|
|
46014
|
+
}
|
|
46015
|
+
break;
|
|
46016
|
+
default:
|
|
46017
|
+
if (error.status >= 500) {
|
|
46018
|
+
message = 'The server encountered an error. Please try again shortly.';
|
|
46019
|
+
}
|
|
46020
|
+
else if (error.status > 0) {
|
|
46021
|
+
message = error.message || 'Something went wrong. Please try again.';
|
|
46022
|
+
}
|
|
46023
|
+
else {
|
|
46024
|
+
message = error.message || 'Unable to connect to the server. Please check your internet connection.';
|
|
46025
|
+
}
|
|
44904
46026
|
}
|
|
44905
|
-
|
|
44906
|
-
|
|
44907
|
-
|
|
44908
|
-
|
|
46027
|
+
return { message, retryAfterSeconds, status: error.status };
|
|
46028
|
+
}
|
|
46029
|
+
if (error instanceof Error) {
|
|
46030
|
+
const lower = error.message.toLowerCase();
|
|
46031
|
+
if (lower.includes('network')) {
|
|
46032
|
+
return { message: 'Unable to connect to the server. Please check your internet connection.' };
|
|
44909
46033
|
}
|
|
44910
|
-
|
|
44911
|
-
|
|
44912
|
-
const status = state.status;
|
|
44913
|
-
if (status === "displaying" || status === "clicked") {
|
|
44914
|
-
return {
|
|
44915
|
-
...entry,
|
|
44916
|
-
action: { ...entry.action, done: true },
|
|
44917
|
-
};
|
|
44918
|
-
}
|
|
46034
|
+
if (lower.includes('timeout')) {
|
|
46035
|
+
return { message: 'The request timed out. Please try again.' };
|
|
44919
46036
|
}
|
|
44920
|
-
|
|
44921
|
-
|
|
44922
|
-
const status = state.status;
|
|
44923
|
-
if (status === "booked" || status === "cancelled" || status === "error") {
|
|
44924
|
-
return {
|
|
44925
|
-
...entry,
|
|
44926
|
-
action: { ...entry.action, done: true },
|
|
44927
|
-
};
|
|
44928
|
-
}
|
|
46037
|
+
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
46038
|
+
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
44929
46039
|
}
|
|
44930
|
-
|
|
44931
|
-
|
|
44932
|
-
}
|
|
44933
|
-
function hydrateMessages(messages) {
|
|
44934
|
-
return hydrateActionDoneStatus(hydrateActionContent(hydrateToolNames(messages)));
|
|
44935
|
-
}
|
|
44936
|
-
function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
|
|
44937
|
-
// Find all incomplete actions and register resume callbacks
|
|
44938
|
-
for (const message of messages) {
|
|
44939
|
-
if (message.action && !message.action.done) {
|
|
44940
|
-
const toolCallId = message.action.toolCallId;
|
|
44941
|
-
const toolName = message.message.name || message.toolExecuting || "tool";
|
|
44942
|
-
registerActionResumeCallback(toolCallId, async (newState) => {
|
|
44943
|
-
// When user interacts with the action after reload, continue the stream
|
|
44944
|
-
try {
|
|
44945
|
-
// Update the action message with the new state
|
|
44946
|
-
setState(prev => ({
|
|
44947
|
-
...prev,
|
|
44948
|
-
messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
|
|
44949
|
-
? {
|
|
44950
|
-
...m,
|
|
44951
|
-
action: m.action ? { ...m.action, state: newState } : undefined,
|
|
44952
|
-
}
|
|
44953
|
-
: m),
|
|
44954
|
-
isTyping: true,
|
|
44955
|
-
}));
|
|
44956
|
-
const streamState = createStreamState();
|
|
44957
|
-
// Continue the agent stream with the new state
|
|
44958
|
-
for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
|
|
44959
|
-
if (event.type === "done") {
|
|
44960
|
-
finalizeToolMessage(streamState, setState, toolCallId, toolName);
|
|
44961
|
-
streamState.sources = event.sources;
|
|
44962
|
-
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
44963
|
-
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
44964
|
-
continue;
|
|
44965
|
-
}
|
|
44966
|
-
if (event.type === "error") {
|
|
44967
|
-
const errorMessage = {
|
|
44968
|
-
id: generateMessageId(),
|
|
44969
|
-
message: {
|
|
44970
|
-
role: "assistant",
|
|
44971
|
-
content: "Sorry, an error occurred. Please try again later.",
|
|
44972
|
-
},
|
|
44973
|
-
timestamp: new Date().toISOString(),
|
|
44974
|
-
sources: [],
|
|
44975
|
-
isError: true,
|
|
44976
|
-
};
|
|
44977
|
-
upsertMessage(setState, errorMessage, false);
|
|
44978
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
44979
|
-
return;
|
|
44980
|
-
}
|
|
44981
|
-
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
44982
|
-
}
|
|
44983
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
44984
|
-
}
|
|
44985
|
-
catch (error) {
|
|
44986
|
-
console.error("[Action Resume] Failed to continue stream:", error);
|
|
44987
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
44988
|
-
}
|
|
44989
|
-
});
|
|
46040
|
+
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
46041
|
+
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
44990
46042
|
}
|
|
46043
|
+
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
44991
46044
|
}
|
|
46045
|
+
return { message: 'Something went wrong. Please try again.' };
|
|
44992
46046
|
}
|
|
46047
|
+
|
|
44993
46048
|
function createStreamState() {
|
|
44994
46049
|
return {
|
|
44995
46050
|
currentContent: "",
|
|
@@ -44998,6 +46053,7 @@
|
|
|
44998
46053
|
newMessageIds: new Set(),
|
|
44999
46054
|
sources: [],
|
|
45000
46055
|
toolCallToActionId: {},
|
|
46056
|
+
requestId: generateMessageId(),
|
|
45001
46057
|
};
|
|
45002
46058
|
}
|
|
45003
46059
|
function upsertMessage(setState, message, isTyping) {
|
|
@@ -45033,15 +46089,40 @@
|
|
|
45033
46089
|
return msg;
|
|
45034
46090
|
}
|
|
45035
46091
|
// Attach suggestions only to the last assistant message
|
|
45036
|
-
|
|
45037
|
-
|
|
45038
|
-
|
|
45039
|
-
return { ...msg, sources, toolCallToActionId };
|
|
46092
|
+
const withSuggestions = index === lastAssistantIndex && suggestions && suggestions.length > 0
|
|
46093
|
+
? { suggestions }
|
|
46094
|
+
: {};
|
|
46095
|
+
return { ...msg, sources, toolCallToActionId, ...withSuggestions };
|
|
45040
46096
|
}),
|
|
45041
46097
|
isTyping: false,
|
|
45042
46098
|
};
|
|
45043
46099
|
});
|
|
45044
46100
|
}
|
|
46101
|
+
function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
|
|
46102
|
+
setState(prev => {
|
|
46103
|
+
const messages = prev.messages.map((entry) => {
|
|
46104
|
+
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
|
|
46105
|
+
if (!matchesToolCall) {
|
|
46106
|
+
return entry;
|
|
46107
|
+
}
|
|
46108
|
+
const existingName = entry.message.name || toolName;
|
|
46109
|
+
return {
|
|
46110
|
+
...entry,
|
|
46111
|
+
message: {
|
|
46112
|
+
role: "tool",
|
|
46113
|
+
content: typeof entry.message.content === "string" ? entry.message.content : "",
|
|
46114
|
+
tool_call_id: toolCallId,
|
|
46115
|
+
name: existingName,
|
|
46116
|
+
},
|
|
46117
|
+
isStreaming: false,
|
|
46118
|
+
toolExecuting: existingName,
|
|
46119
|
+
};
|
|
46120
|
+
});
|
|
46121
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
46122
|
+
});
|
|
46123
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
46124
|
+
}
|
|
46125
|
+
|
|
45045
46126
|
function handleContentEvent(event, streamState, onMessageUpdate, setState) {
|
|
45046
46127
|
streamState.currentContent += event.content;
|
|
45047
46128
|
const assistantMessage = {
|
|
@@ -45088,8 +46169,6 @@
|
|
|
45088
46169
|
}
|
|
45089
46170
|
function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
45090
46171
|
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
45091
|
-
// Update state and mark action as done in a single setState call
|
|
45092
|
-
// Keep isTyping: true because the agent may continue generating content after tool completion
|
|
45093
46172
|
setState(prev => {
|
|
45094
46173
|
const messages = prev.messages.map((msg) => {
|
|
45095
46174
|
const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
|
|
@@ -45097,7 +46176,27 @@
|
|
|
45097
46176
|
return msg;
|
|
45098
46177
|
}
|
|
45099
46178
|
const existingName = msg.message.name || event.tool_name;
|
|
45100
|
-
|
|
46179
|
+
let action = msg.action;
|
|
46180
|
+
if (event.action_id && event.implementation) {
|
|
46181
|
+
action = {
|
|
46182
|
+
...action,
|
|
46183
|
+
implementation: event.implementation,
|
|
46184
|
+
toolCallId: event.tool_call_id,
|
|
46185
|
+
actionId: event.action_id,
|
|
46186
|
+
input: (event.input || {}),
|
|
46187
|
+
state: (event.state || {}),
|
|
46188
|
+
done: event.done,
|
|
46189
|
+
};
|
|
46190
|
+
}
|
|
46191
|
+
else if (action) {
|
|
46192
|
+
action = {
|
|
46193
|
+
...action,
|
|
46194
|
+
input: event.input ? event.input : action.input,
|
|
46195
|
+
state: event.state ? event.state : action.state,
|
|
46196
|
+
done: event.done,
|
|
46197
|
+
};
|
|
46198
|
+
}
|
|
46199
|
+
const updatedMsg = {
|
|
45101
46200
|
...msg,
|
|
45102
46201
|
message: {
|
|
45103
46202
|
role: "tool",
|
|
@@ -45107,14 +46206,10 @@
|
|
|
45107
46206
|
},
|
|
45108
46207
|
isStreaming: false,
|
|
45109
46208
|
toolExecuting: existingName,
|
|
45110
|
-
action
|
|
45111
|
-
...msg.action,
|
|
45112
|
-
state: event.state || msg.action.state,
|
|
45113
|
-
done: true, // Mark action as completed
|
|
45114
|
-
} : undefined,
|
|
46209
|
+
action,
|
|
45115
46210
|
};
|
|
46211
|
+
return updatedMsg;
|
|
45116
46212
|
});
|
|
45117
|
-
// Keep typing indicator visible - it will be hidden by done/finalizeStreamMessages
|
|
45118
46213
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
45119
46214
|
});
|
|
45120
46215
|
}
|
|
@@ -45146,34 +46241,6 @@
|
|
|
45146
46241
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
45147
46242
|
});
|
|
45148
46243
|
}
|
|
45149
|
-
function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
|
|
45150
|
-
setState(prev => {
|
|
45151
|
-
const messages = prev.messages.map((entry) => {
|
|
45152
|
-
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
|
|
45153
|
-
if (!matchesToolCall) {
|
|
45154
|
-
return entry;
|
|
45155
|
-
}
|
|
45156
|
-
const existingName = entry.message.name || toolName;
|
|
45157
|
-
return {
|
|
45158
|
-
...entry,
|
|
45159
|
-
message: {
|
|
45160
|
-
role: "tool",
|
|
45161
|
-
content: typeof entry.message.content === "string" ? entry.message.content : "",
|
|
45162
|
-
tool_call_id: toolCallId,
|
|
45163
|
-
name: existingName,
|
|
45164
|
-
},
|
|
45165
|
-
isStreaming: false,
|
|
45166
|
-
toolExecuting: existingName,
|
|
45167
|
-
action: entry.action ? {
|
|
45168
|
-
...entry.action,
|
|
45169
|
-
done: true, // Mark action as completed
|
|
45170
|
-
} : undefined,
|
|
45171
|
-
};
|
|
45172
|
-
});
|
|
45173
|
-
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
45174
|
-
});
|
|
45175
|
-
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
45176
|
-
}
|
|
45177
46244
|
function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
|
|
45178
46245
|
streamState.sources = event.sources;
|
|
45179
46246
|
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
@@ -45232,6 +46299,10 @@
|
|
|
45232
46299
|
console.warn('[Chat] Unknown event type:', event.type);
|
|
45233
46300
|
}
|
|
45234
46301
|
}
|
|
46302
|
+
|
|
46303
|
+
function isDismissedState(state) {
|
|
46304
|
+
return Boolean(state.__dismissed);
|
|
46305
|
+
}
|
|
45235
46306
|
async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
|
|
45236
46307
|
let pendingEvent = initialEvent;
|
|
45237
46308
|
while (pendingEvent) {
|
|
@@ -45258,7 +46329,7 @@
|
|
|
45258
46329
|
actionId: pendingEvent.action_id,
|
|
45259
46330
|
input: pendingEvent.input,
|
|
45260
46331
|
state: pendingEvent.state,
|
|
45261
|
-
done: false,
|
|
46332
|
+
done: pendingEvent.done ?? false,
|
|
45262
46333
|
},
|
|
45263
46334
|
};
|
|
45264
46335
|
if (streamState.activeToolCallCount === 0) {
|
|
@@ -45272,7 +46343,7 @@
|
|
|
45272
46343
|
id: generateMessageId(),
|
|
45273
46344
|
message: {
|
|
45274
46345
|
role: "assistant",
|
|
45275
|
-
content: "Sorry, an error occurred.
|
|
46346
|
+
content: "Sorry, an error occurred.",
|
|
45276
46347
|
},
|
|
45277
46348
|
timestamp: new Date().toISOString(),
|
|
45278
46349
|
sources: [],
|
|
@@ -45296,7 +46367,7 @@
|
|
|
45296
46367
|
console.error("[Widget] Frontend action failed:", error);
|
|
45297
46368
|
const errorMessageEntry = {
|
|
45298
46369
|
id: generateMessageId(),
|
|
45299
|
-
message: { role: "assistant", content: "Sorry, an error occurred.
|
|
46370
|
+
message: { role: "assistant", content: "Sorry, an error occurred." },
|
|
45300
46371
|
timestamp: new Date().toISOString(),
|
|
45301
46372
|
sources: [],
|
|
45302
46373
|
isError: true,
|
|
@@ -45306,16 +46377,17 @@
|
|
|
45306
46377
|
return;
|
|
45307
46378
|
}
|
|
45308
46379
|
pendingEvent = null;
|
|
45309
|
-
const
|
|
45310
|
-
|
|
45311
|
-
|
|
45312
|
-
|
|
45313
|
-
|
|
45314
|
-
|
|
45315
|
-
|
|
45316
|
-
|
|
45317
|
-
|
|
45318
|
-
|
|
46380
|
+
const dismissed = isDismissedState(nextState);
|
|
46381
|
+
if (!dismissed) {
|
|
46382
|
+
const updatedToolMessage = {
|
|
46383
|
+
...toolMessage,
|
|
46384
|
+
action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
|
|
46385
|
+
};
|
|
46386
|
+
upsertMessage(setState, updatedToolMessage, true);
|
|
46387
|
+
}
|
|
46388
|
+
if (dismissed) {
|
|
46389
|
+
return;
|
|
46390
|
+
}
|
|
45319
46391
|
let streamEnded = false;
|
|
45320
46392
|
for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
|
|
45321
46393
|
if (event.type === "action_request") {
|
|
@@ -45323,22 +46395,20 @@
|
|
|
45323
46395
|
break;
|
|
45324
46396
|
}
|
|
45325
46397
|
if (event.type === "done") {
|
|
45326
|
-
//
|
|
45327
|
-
// updated by tool_end event or by the user's frontend action.
|
|
46398
|
+
// Finalize tool message and stream messages
|
|
45328
46399
|
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
45329
|
-
// Handle the done event but skip the tool finalization part since we already did it
|
|
45330
46400
|
streamState.sources = event.sources;
|
|
45331
46401
|
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
45332
46402
|
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
45333
46403
|
streamEnded = true;
|
|
45334
|
-
continue;
|
|
46404
|
+
continue;
|
|
45335
46405
|
}
|
|
45336
46406
|
if (event.type === "error") {
|
|
45337
46407
|
const errorMessage = {
|
|
45338
46408
|
id: generateMessageId(),
|
|
45339
46409
|
message: {
|
|
45340
46410
|
role: "assistant",
|
|
45341
|
-
content: "Sorry, an error occurred.
|
|
46411
|
+
content: "Sorry, an error occurred.",
|
|
45342
46412
|
},
|
|
45343
46413
|
timestamp: new Date().toISOString(),
|
|
45344
46414
|
sources: [],
|
|
@@ -45349,73 +46419,83 @@
|
|
|
45349
46419
|
}
|
|
45350
46420
|
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
45351
46421
|
}
|
|
45352
|
-
// If stream ended without a done event
|
|
46422
|
+
// If stream ended without a done event, finalize the tool message
|
|
45353
46423
|
if (!streamEnded && !pendingEvent) {
|
|
45354
46424
|
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
45355
46425
|
}
|
|
45356
46426
|
}
|
|
45357
46427
|
}
|
|
45358
|
-
function
|
|
45359
|
-
|
|
45360
|
-
|
|
45361
|
-
|
|
45362
|
-
|
|
45363
|
-
|
|
45364
|
-
|
|
45365
|
-
|
|
45366
|
-
|
|
45367
|
-
|
|
45368
|
-
|
|
45369
|
-
|
|
45370
|
-
|
|
45371
|
-
|
|
45372
|
-
|
|
45373
|
-
|
|
45374
|
-
|
|
45375
|
-
|
|
45376
|
-
|
|
45377
|
-
|
|
45378
|
-
|
|
45379
|
-
|
|
45380
|
-
|
|
45381
|
-
|
|
45382
|
-
|
|
45383
|
-
|
|
45384
|
-
|
|
45385
|
-
|
|
45386
|
-
|
|
45387
|
-
|
|
45388
|
-
|
|
45389
|
-
|
|
45390
|
-
|
|
45391
|
-
|
|
45392
|
-
|
|
45393
|
-
|
|
46428
|
+
function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate, createStreamState, registerCallback) {
|
|
46429
|
+
// Find all incomplete actions and register resume callbacks
|
|
46430
|
+
for (const message of messages) {
|
|
46431
|
+
if (message.action && !message.action.done && !message.action.hidden) {
|
|
46432
|
+
const toolCallId = message.action.toolCallId;
|
|
46433
|
+
const toolName = message.message.name || message.toolExecuting || "tool";
|
|
46434
|
+
registerCallback(toolCallId, async (newState) => {
|
|
46435
|
+
// When user interacts with the action after reload, continue the stream
|
|
46436
|
+
try {
|
|
46437
|
+
// Update the action message with the new state and check completion
|
|
46438
|
+
if (isDismissedState(newState)) {
|
|
46439
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
46440
|
+
return;
|
|
46441
|
+
}
|
|
46442
|
+
setState(prev => ({
|
|
46443
|
+
...prev,
|
|
46444
|
+
messages: prev.messages.map(m => {
|
|
46445
|
+
if (m.action?.toolCallId !== toolCallId) {
|
|
46446
|
+
return m;
|
|
46447
|
+
}
|
|
46448
|
+
if (!m.action) {
|
|
46449
|
+
return m;
|
|
46450
|
+
}
|
|
46451
|
+
return { ...m, action: { ...m.action, state: newState } };
|
|
46452
|
+
}),
|
|
46453
|
+
isTyping: true,
|
|
46454
|
+
}));
|
|
46455
|
+
const streamState = createStreamState();
|
|
46456
|
+
// Continue the agent stream with the new state
|
|
46457
|
+
for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
|
|
46458
|
+
if (event.type === "done") {
|
|
46459
|
+
finalizeToolMessage(streamState, setState, toolCallId, toolName);
|
|
46460
|
+
streamState.sources = event.sources;
|
|
46461
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
46462
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
46463
|
+
continue;
|
|
46464
|
+
}
|
|
46465
|
+
if (event.type === "error") {
|
|
46466
|
+
const errorMessage = {
|
|
46467
|
+
id: generateMessageId(),
|
|
46468
|
+
message: {
|
|
46469
|
+
role: "assistant",
|
|
46470
|
+
content: "Sorry, an error occurred. Please try again later.",
|
|
46471
|
+
},
|
|
46472
|
+
timestamp: new Date().toISOString(),
|
|
46473
|
+
sources: [],
|
|
46474
|
+
isError: true,
|
|
46475
|
+
};
|
|
46476
|
+
upsertMessage(setState, errorMessage, false);
|
|
46477
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
46478
|
+
return;
|
|
46479
|
+
}
|
|
46480
|
+
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
46481
|
+
}
|
|
46482
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
45394
46483
|
}
|
|
45395
|
-
|
|
45396
|
-
|
|
46484
|
+
catch (error) {
|
|
46485
|
+
console.error("[Action Resume] Failed to continue stream:", error);
|
|
46486
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
45397
46487
|
}
|
|
46488
|
+
});
|
|
45398
46489
|
}
|
|
45399
|
-
return { message, retryAfterSeconds, status: error.status };
|
|
45400
|
-
}
|
|
45401
|
-
if (error instanceof Error) {
|
|
45402
|
-
const lower = error.message.toLowerCase();
|
|
45403
|
-
if (lower.includes('network')) {
|
|
45404
|
-
return { message: 'Unable to connect to the server. Please check your internet connection.' };
|
|
45405
|
-
}
|
|
45406
|
-
if (lower.includes('timeout')) {
|
|
45407
|
-
return { message: 'The request timed out. Please try again.' };
|
|
45408
|
-
}
|
|
45409
|
-
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
45410
|
-
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
45411
|
-
}
|
|
45412
|
-
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
45413
|
-
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
45414
|
-
}
|
|
45415
|
-
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
45416
46490
|
}
|
|
45417
|
-
return { message: 'Something went wrong. Please try again.' };
|
|
45418
46491
|
}
|
|
46492
|
+
|
|
46493
|
+
/**
|
|
46494
|
+
* useChat Hook
|
|
46495
|
+
* Main state management for chat functionality
|
|
46496
|
+
*/
|
|
46497
|
+
// Initialize action handlers immediately to prevent tree-shaking
|
|
46498
|
+
initializeActionHandlers();
|
|
45419
46499
|
function useChat(options) {
|
|
45420
46500
|
const { widgetId, apiUrl, currentRoute, onMessage, onError, skipInitialization = false, } = options;
|
|
45421
46501
|
const [state, setState] = reactExports.useState({
|
|
@@ -45424,27 +46504,24 @@
|
|
|
45424
46504
|
isLoading: false,
|
|
45425
46505
|
isTyping: false,
|
|
45426
46506
|
error: null,
|
|
45427
|
-
conversationId: '',
|
|
46507
|
+
conversationId: '',
|
|
45428
46508
|
config: null,
|
|
45429
46509
|
});
|
|
45430
46510
|
const stateRef = reactExports.useRef(state);
|
|
45431
46511
|
reactExports.useEffect(() => {
|
|
45432
46512
|
stateRef.current = state;
|
|
45433
46513
|
}, [state]);
|
|
45434
|
-
// Chat history state
|
|
45435
46514
|
const [conversations, setConversations] = reactExports.useState([]);
|
|
45436
|
-
// Stream cancellation and rate limiting
|
|
45437
46515
|
const abortControllerRef = reactExports.useRef(null);
|
|
46516
|
+
const currentRequestIdRef = reactExports.useRef(null);
|
|
45438
46517
|
const lastNewChatTimeRef = reactExports.useRef(0);
|
|
45439
|
-
const NEW_CHAT_COOLDOWN_MS = 5000;
|
|
46518
|
+
const NEW_CHAT_COOLDOWN_MS = 5000;
|
|
45440
46519
|
const apiClient = reactExports.useRef(new WidgetApiClient({ widgetId, apiUrl, currentRoute }));
|
|
45441
|
-
// Update API client when currentRoute changes
|
|
45442
46520
|
reactExports.useEffect(() => {
|
|
45443
46521
|
apiClient.current = new WidgetApiClient({ widgetId, apiUrl, currentRoute });
|
|
45444
46522
|
}, [widgetId, apiUrl, currentRoute]);
|
|
45445
46523
|
// Load configuration on mount and hydrate with existing conversation if available
|
|
45446
46524
|
reactExports.useEffect(() => {
|
|
45447
|
-
// Skip initialization in preview mode
|
|
45448
46525
|
if (skipInitialization) {
|
|
45449
46526
|
return;
|
|
45450
46527
|
}
|
|
@@ -45481,7 +46558,7 @@
|
|
|
45481
46558
|
}));
|
|
45482
46559
|
// Setup resume callbacks for incomplete actions
|
|
45483
46560
|
if (conversationId) {
|
|
45484
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
|
|
46561
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
45485
46562
|
}
|
|
45486
46563
|
}
|
|
45487
46564
|
catch (error) {
|
|
@@ -45498,14 +46575,13 @@
|
|
|
45498
46575
|
initialize();
|
|
45499
46576
|
return () => {
|
|
45500
46577
|
isMounted = false;
|
|
45501
|
-
// Cleanup resume callbacks
|
|
45502
46578
|
state.messages.forEach(message => {
|
|
45503
46579
|
if (message.action?.toolCallId) {
|
|
45504
46580
|
unregisterActionResumeCallback(message.action.toolCallId);
|
|
45505
46581
|
}
|
|
45506
46582
|
});
|
|
45507
46583
|
};
|
|
45508
|
-
}, [widgetId, apiUrl, onError]);
|
|
46584
|
+
}, [widgetId, apiUrl, onError, skipInitialization]);
|
|
45509
46585
|
// Save conversation when messages change
|
|
45510
46586
|
reactExports.useEffect(() => {
|
|
45511
46587
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
@@ -45521,19 +46597,15 @@
|
|
|
45521
46597
|
const hasFiles = !!files && files.length > 0;
|
|
45522
46598
|
if (!trimmedContent && !hasFiles)
|
|
45523
46599
|
return;
|
|
45524
|
-
// Block parallel streams - don't allow sending while already streaming
|
|
45525
46600
|
if (stateRef.current.isTyping) {
|
|
45526
46601
|
console.warn('[Widget] Cannot send message while streaming is in progress');
|
|
45527
46602
|
return;
|
|
45528
46603
|
}
|
|
45529
|
-
// Cancel any existing stream before starting new one
|
|
45530
46604
|
if (abortControllerRef.current) {
|
|
45531
46605
|
abortControllerRef.current.abort();
|
|
45532
46606
|
abortControllerRef.current = null;
|
|
45533
46607
|
}
|
|
45534
|
-
// Create new abort controller for this stream
|
|
45535
46608
|
abortControllerRef.current = new AbortController();
|
|
45536
|
-
// Strip [EXECUTE_ACTION:...] prefix from displayed message (but keep for API)
|
|
45537
46609
|
const displayContent = trimmedContent.replace(/^\[EXECUTE_ACTION:[^\]]+\]\s*/, '');
|
|
45538
46610
|
const userMessage = {
|
|
45539
46611
|
id: generateMessageId(),
|
|
@@ -45544,12 +46616,11 @@
|
|
|
45544
46616
|
timestamp: new Date().toISOString(),
|
|
45545
46617
|
sources: [],
|
|
45546
46618
|
};
|
|
45547
|
-
// Add user message immediately
|
|
45548
46619
|
setState(prev => ({
|
|
45549
46620
|
...prev,
|
|
45550
46621
|
messages: [...prev.messages, userMessage],
|
|
45551
|
-
isLoading: false,
|
|
45552
|
-
isTyping: true,
|
|
46622
|
+
isLoading: false,
|
|
46623
|
+
isTyping: true,
|
|
45553
46624
|
error: null,
|
|
45554
46625
|
}));
|
|
45555
46626
|
onMessage?.(userMessage);
|
|
@@ -45589,26 +46660,27 @@
|
|
|
45589
46660
|
}
|
|
45590
46661
|
catch (uploadError) {
|
|
45591
46662
|
console.error('Failed to upload file:', uploadError);
|
|
45592
|
-
// Continue with other files
|
|
45593
46663
|
}
|
|
45594
46664
|
}
|
|
45595
46665
|
}
|
|
45596
|
-
// Stream the response
|
|
45597
46666
|
let lastStreamedMessage = null;
|
|
45598
46667
|
const streamState = createStreamState();
|
|
45599
|
-
|
|
46668
|
+
currentRequestIdRef.current = streamState.requestId;
|
|
45600
46669
|
const currentAbortController = abortControllerRef.current;
|
|
45601
46670
|
const streamConversationId = conversationId;
|
|
45602
|
-
const
|
|
46671
|
+
const streamRequestId = streamState.requestId;
|
|
46672
|
+
const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds, currentAbortController?.signal);
|
|
45603
46673
|
for await (const event of stream) {
|
|
45604
|
-
|
|
45605
|
-
|
|
45606
|
-
|
|
46674
|
+
if (currentAbortController?.signal.aborted ||
|
|
46675
|
+
stateRef.current.conversationId !== streamConversationId ||
|
|
46676
|
+
currentRequestIdRef.current !== streamRequestId) {
|
|
46677
|
+
console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
|
|
45607
46678
|
break;
|
|
45608
46679
|
}
|
|
45609
46680
|
if (event.type === "action_request") {
|
|
45610
|
-
|
|
45611
|
-
|
|
46681
|
+
if (currentAbortController?.signal.aborted ||
|
|
46682
|
+
stateRef.current.conversationId !== streamConversationId ||
|
|
46683
|
+
currentRequestIdRef.current !== streamRequestId) {
|
|
45612
46684
|
break;
|
|
45613
46685
|
}
|
|
45614
46686
|
await handleActionLoop(apiClient.current, event, streamState, (message) => {
|
|
@@ -45620,30 +46692,26 @@
|
|
|
45620
46692
|
lastStreamedMessage = message;
|
|
45621
46693
|
}, setState);
|
|
45622
46694
|
}
|
|
45623
|
-
|
|
45624
|
-
|
|
45625
|
-
|
|
46695
|
+
if (currentAbortController?.signal.aborted ||
|
|
46696
|
+
stateRef.current.conversationId !== streamConversationId ||
|
|
46697
|
+
currentRequestIdRef.current !== streamRequestId) {
|
|
46698
|
+
console.log('[Widget] Stream was aborted or superseded, skipping finalization');
|
|
45626
46699
|
return;
|
|
45627
46700
|
}
|
|
45628
|
-
// Stream completed - finalize state
|
|
45629
46701
|
setState(prev => ({
|
|
45630
46702
|
...prev,
|
|
45631
46703
|
isLoading: false,
|
|
45632
46704
|
isTyping: false,
|
|
45633
46705
|
}));
|
|
45634
|
-
// Notify about final message
|
|
45635
46706
|
if (lastStreamedMessage) {
|
|
45636
46707
|
onMessage?.(lastStreamedMessage);
|
|
45637
46708
|
}
|
|
45638
|
-
// Generate follow-up suggestions asynchronously
|
|
45639
46709
|
const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
|
|
45640
46710
|
const actionIds = state.config?.actions || [];
|
|
45641
46711
|
if (enableFollowUps) {
|
|
45642
|
-
// Don't await - let it run in background
|
|
45643
46712
|
apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
|
|
45644
46713
|
.then(suggestions => {
|
|
45645
46714
|
if (suggestions.length > 0) {
|
|
45646
|
-
// Attach suggestions to the last assistant message
|
|
45647
46715
|
setState(prev => {
|
|
45648
46716
|
const messages = [...prev.messages];
|
|
45649
46717
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -45672,7 +46740,7 @@
|
|
|
45672
46740
|
},
|
|
45673
46741
|
timestamp: new Date().toISOString(),
|
|
45674
46742
|
sources: [],
|
|
45675
|
-
isError: !fallbackMessage,
|
|
46743
|
+
isError: !fallbackMessage,
|
|
45676
46744
|
};
|
|
45677
46745
|
setState(prev => ({
|
|
45678
46746
|
...prev,
|
|
@@ -45684,9 +46752,6 @@
|
|
|
45684
46752
|
onError?.(err);
|
|
45685
46753
|
}
|
|
45686
46754
|
}, [state.conversationId, state.config, state.messages, onMessage, onError]);
|
|
45687
|
-
/**
|
|
45688
|
-
* Clear all messages
|
|
45689
|
-
*/
|
|
45690
46755
|
const clearMessages = reactExports.useCallback(() => {
|
|
45691
46756
|
setState(prev => ({
|
|
45692
46757
|
...prev,
|
|
@@ -45699,9 +46764,6 @@
|
|
|
45699
46764
|
clearConversation(widgetId);
|
|
45700
46765
|
}
|
|
45701
46766
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
45702
|
-
/**
|
|
45703
|
-
* Submit feedback for a message
|
|
45704
|
-
*/
|
|
45705
46767
|
const submitFeedback = reactExports.useCallback(async (messageId, feedback) => {
|
|
45706
46768
|
try {
|
|
45707
46769
|
const message = state.messages.find(msg => msg.id === messageId);
|
|
@@ -45711,7 +46773,6 @@
|
|
|
45711
46773
|
: undefined;
|
|
45712
46774
|
console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
|
|
45713
46775
|
await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
|
|
45714
|
-
// Update message with feedback
|
|
45715
46776
|
setState(prev => ({
|
|
45716
46777
|
...prev,
|
|
45717
46778
|
messages: prev.messages.map(msg => msg.id === messageId
|
|
@@ -45726,9 +46787,51 @@
|
|
|
45726
46787
|
onError?.(err);
|
|
45727
46788
|
}
|
|
45728
46789
|
}, [state.conversationId, onError]);
|
|
45729
|
-
|
|
45730
|
-
|
|
45731
|
-
|
|
46790
|
+
const dismissAction = reactExports.useCallback(async (toolCallId) => {
|
|
46791
|
+
if (!toolCallId)
|
|
46792
|
+
return;
|
|
46793
|
+
const dismissedAt = new Date().toISOString();
|
|
46794
|
+
setState(prev => ({
|
|
46795
|
+
...prev,
|
|
46796
|
+
messages: prev.messages.map((message) => {
|
|
46797
|
+
if (message.action?.toolCallId !== toolCallId) {
|
|
46798
|
+
return message;
|
|
46799
|
+
}
|
|
46800
|
+
if (!message.action) {
|
|
46801
|
+
return message;
|
|
46802
|
+
}
|
|
46803
|
+
return {
|
|
46804
|
+
...message,
|
|
46805
|
+
action: {
|
|
46806
|
+
...message.action,
|
|
46807
|
+
hidden: true,
|
|
46808
|
+
dismissedAt,
|
|
46809
|
+
dismissedBy: "user",
|
|
46810
|
+
done: true,
|
|
46811
|
+
},
|
|
46812
|
+
};
|
|
46813
|
+
}),
|
|
46814
|
+
isTyping: true,
|
|
46815
|
+
isLoading: false,
|
|
46816
|
+
}));
|
|
46817
|
+
unregisterActionResumeCallback(toolCallId);
|
|
46818
|
+
const conversationId = stateRef.current.conversationId;
|
|
46819
|
+
if (!conversationId) {
|
|
46820
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
46821
|
+
return;
|
|
46822
|
+
}
|
|
46823
|
+
try {
|
|
46824
|
+
const streamState = createStreamState();
|
|
46825
|
+
for await (const event of apiClient.current.dismissAgentMessageStream(conversationId, toolCallId)) {
|
|
46826
|
+
handleStreamEvent(event, streamState, onMessage ?? (() => { }), setState);
|
|
46827
|
+
}
|
|
46828
|
+
setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
|
|
46829
|
+
}
|
|
46830
|
+
catch (error) {
|
|
46831
|
+
console.error("[Widget] dismissAction error:", error);
|
|
46832
|
+
setState(prev => ({ ...prev, isTyping: false, isLoading: false }));
|
|
46833
|
+
}
|
|
46834
|
+
}, [onMessage]);
|
|
45732
46835
|
const loadConversations = reactExports.useCallback(() => {
|
|
45733
46836
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
45734
46837
|
if (!persistConversation || !isStorageAvailable()) {
|
|
@@ -45745,13 +46848,11 @@
|
|
|
45745
46848
|
})));
|
|
45746
46849
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
45747
46850
|
const switchConversation = reactExports.useCallback(async (conversationId) => {
|
|
45748
|
-
// Cancel any active stream before switching conversations
|
|
45749
46851
|
if (abortControllerRef.current) {
|
|
45750
46852
|
abortControllerRef.current.abort();
|
|
45751
46853
|
abortControllerRef.current = null;
|
|
45752
46854
|
}
|
|
45753
46855
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
45754
|
-
// First try to load from localStorage
|
|
45755
46856
|
if (persistConversation && isStorageAvailable()) {
|
|
45756
46857
|
const stored = loadConversationById(widgetId, conversationId);
|
|
45757
46858
|
if (stored) {
|
|
@@ -45770,7 +46871,6 @@
|
|
|
45770
46871
|
try {
|
|
45771
46872
|
const conversation = await apiClient.current.getOrCreateConversation(conversationId);
|
|
45772
46873
|
const hydratedMessages = hydrateMessages(conversation.messages);
|
|
45773
|
-
// Clear old resume callbacks
|
|
45774
46874
|
state.messages.forEach(message => {
|
|
45775
46875
|
if (message.action?.toolCallId) {
|
|
45776
46876
|
unregisterActionResumeCallback(message.action.toolCallId);
|
|
@@ -45782,9 +46882,7 @@
|
|
|
45782
46882
|
messages: hydratedMessages,
|
|
45783
46883
|
isLoading: false,
|
|
45784
46884
|
}));
|
|
45785
|
-
|
|
45786
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
|
|
45787
|
-
// Save to local storage
|
|
46885
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
45788
46886
|
if (persistConversation && isStorageAvailable()) {
|
|
45789
46887
|
saveConversation(widgetId, conversation.id, hydratedMessages);
|
|
45790
46888
|
}
|
|
@@ -45795,19 +46893,16 @@
|
|
|
45795
46893
|
}
|
|
45796
46894
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
45797
46895
|
const startNewConversation = reactExports.useCallback(() => {
|
|
45798
|
-
// Rate limiting - prevent spamming new chats
|
|
45799
46896
|
const now = Date.now();
|
|
45800
46897
|
if (now - lastNewChatTimeRef.current < NEW_CHAT_COOLDOWN_MS) {
|
|
45801
46898
|
console.warn('[Widget] New chat rate limited - please wait');
|
|
45802
46899
|
return;
|
|
45803
46900
|
}
|
|
45804
46901
|
lastNewChatTimeRef.current = now;
|
|
45805
|
-
// Cancel any active stream before starting new conversation
|
|
45806
46902
|
if (abortControllerRef.current) {
|
|
45807
46903
|
abortControllerRef.current.abort();
|
|
45808
46904
|
abortControllerRef.current = null;
|
|
45809
46905
|
}
|
|
45810
|
-
// Reset typing state if stream was active
|
|
45811
46906
|
setState(prev => ({
|
|
45812
46907
|
...prev,
|
|
45813
46908
|
messages: [],
|
|
@@ -45826,11 +46921,8 @@
|
|
|
45826
46921
|
if (!persistConversation || !isStorageAvailable()) {
|
|
45827
46922
|
return;
|
|
45828
46923
|
}
|
|
45829
|
-
// Delete from storage
|
|
45830
46924
|
deleteConversation(widgetId, conversationId);
|
|
45831
|
-
// Update local state
|
|
45832
46925
|
setConversations(prev => prev.filter(c => c.id !== conversationId));
|
|
45833
|
-
// If we deleted the current conversation, clear it
|
|
45834
46926
|
if (state.conversationId === conversationId) {
|
|
45835
46927
|
setState(prev => ({
|
|
45836
46928
|
...prev,
|
|
@@ -45840,6 +46932,43 @@
|
|
|
45840
46932
|
}));
|
|
45841
46933
|
}
|
|
45842
46934
|
}, [widgetId, state.config?.settings.persistConversation, state.conversationId]);
|
|
46935
|
+
const createDemoConversation = reactExports.useCallback(async (userMessage, assistantMessage) => {
|
|
46936
|
+
try {
|
|
46937
|
+
const result = await apiClient.current.createDemoConversation(userMessage, assistantMessage);
|
|
46938
|
+
if (result.success && result.id) {
|
|
46939
|
+
// Update state with the new conversation ID
|
|
46940
|
+
setState(prev => ({
|
|
46941
|
+
...prev,
|
|
46942
|
+
conversationId: result.id,
|
|
46943
|
+
}));
|
|
46944
|
+
// Save to local storage if persistence is enabled
|
|
46945
|
+
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
46946
|
+
if (persistConversation && isStorageAvailable()) {
|
|
46947
|
+
const demoMessages = [
|
|
46948
|
+
{
|
|
46949
|
+
id: generateMessageId(),
|
|
46950
|
+
message: { role: 'user', content: userMessage },
|
|
46951
|
+
timestamp: new Date().toISOString(),
|
|
46952
|
+
sources: [],
|
|
46953
|
+
},
|
|
46954
|
+
{
|
|
46955
|
+
id: generateMessageId(),
|
|
46956
|
+
message: { role: 'assistant', content: assistantMessage },
|
|
46957
|
+
timestamp: new Date(Date.now() + 1000).toISOString(),
|
|
46958
|
+
sources: [],
|
|
46959
|
+
},
|
|
46960
|
+
];
|
|
46961
|
+
saveConversation(widgetId, result.id, demoMessages);
|
|
46962
|
+
}
|
|
46963
|
+
return result.id;
|
|
46964
|
+
}
|
|
46965
|
+
return null;
|
|
46966
|
+
}
|
|
46967
|
+
catch (error) {
|
|
46968
|
+
console.error('[useChat] Failed to create demo conversation:', error);
|
|
46969
|
+
return null;
|
|
46970
|
+
}
|
|
46971
|
+
}, [widgetId, state.config?.settings.persistConversation]);
|
|
45843
46972
|
return {
|
|
45844
46973
|
messages: state.messages,
|
|
45845
46974
|
isLoading: state.isLoading,
|
|
@@ -45850,20 +46979,29 @@
|
|
|
45850
46979
|
sendMessage,
|
|
45851
46980
|
clearMessages,
|
|
45852
46981
|
submitFeedback,
|
|
45853
|
-
|
|
46982
|
+
dismissAction,
|
|
45854
46983
|
conversations,
|
|
45855
46984
|
loadConversations,
|
|
45856
46985
|
switchConversation,
|
|
45857
46986
|
startNewConversation,
|
|
45858
46987
|
deleteConversation: deleteConversation$1,
|
|
46988
|
+
createDemoConversation,
|
|
45859
46989
|
};
|
|
45860
46990
|
}
|
|
45861
46991
|
|
|
46992
|
+
const DataPolicyView = ({ config, widgetName, }) => {
|
|
46993
|
+
const headerTitle = widgetName || config?.appearance?.headerTitle || 'AI Assistant';
|
|
46994
|
+
const hasFileUpload = config?.settings?.enableFileUpload ?? false;
|
|
46995
|
+
const persistsConversation = config?.settings?.persistConversation ?? true;
|
|
46996
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-data-policy-view", children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-content", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-data-policy-intro", children: jsxRuntimeExports.jsxs("p", { children: ["This privacy notice informs you pursuant to Art. 13 GDPR about how ", jsxRuntimeExports.jsx("strong", { children: headerTitle }), " processes data when you use this chat. Please note that the specific scope of processing depends on the operator of this website/application (the controller) and on the respective activated functions."] }) }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Controller / Contact" }), jsxRuntimeExports.jsx("p", { children: "The controller within the meaning of Art. 4 No. 7 GDPR is the operator of this website/application. The contact details (and, if applicable, the contact details of a data protection officer) can be found in the privacy policy or in the legal notice of the website into which this chat widget is embedded." })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Processed Data" }), jsxRuntimeExports.jsxs("p", { children: ["The chat processes the following categories of data. ", jsxRuntimeExports.jsx("strong", { children: "Chat Content" }), " comprises messages (text) and, if applicable, context information that you provide in the chat. This content is processed to generate responses and provide the conversation."] }), hasFileUpload && (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Uploaded Files" }), " that you transmit to the chat are processed to handle your request. Processing may include extracting text or information."] })), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Technical Usage Data" }), " includes timestamps, session or request information, as well as technical metadata required for operation, security (abuse prevention), and error analysis."] }), jsxRuntimeExports.jsx("p", { children: "Please do not enter special categories of personal data (e.g., health data), passwords, credit card or bank data, or confidential business secrets in the chat. AI-generated responses may be inaccurate and should be checked independently before use." })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Purposes and Legal Bases" }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Provision of the chat and answering of inquiries" }), " is based on Art. 6 Para. 1 lit. b GDPR, insofar as contractual or pre-contractual measures apply; otherwise on Art. 6 Para. 1 lit. f GDPR (legitimate interest in efficient communication and support)."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Quality assurance, operation and security" }), " are based on Art. 6 Para. 1 lit. f GDPR, for example for stability, abuse detection, and troubleshooting."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Consent-based processing" }), " may occur if the operator provides for this (Art. 6 Para. 1 lit. a GDPR)."] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Recipients and Processors" }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Hosting/IT Service Providers" }), " may be used by the operator for hosting, logging, monitoring, and infrastructure."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "AI Service Providers" }), " may receive chat content to generate responses. Where required, this is done on the basis of a data processing agreement (Art. 28 GDPR)."] }), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Third-Country Transfer" }), " may occur if recipients are located outside the EU/EEA. In this case, appropriate safeguards (e.g., EU Standard Contractual Clauses) are used where required."] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Retention Period" }), persistsConversation ? (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Chat History" }), " may be stored to continue the conversation across multiple sessions."] })) : (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Chat History" }), " is not permanently stored and ends when the chat is closed."] })), hasFileUpload && (jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Files" }), " are processed only as long as necessary to handle the request and are then deleted, unless longer retention is legally required."] })), jsxRuntimeExports.jsxs("p", { children: [jsxRuntimeExports.jsx("strong", { children: "Technical Logs" }), " may be stored for a limited period to ensure secure operation."] })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-data-policy-section", children: [jsxRuntimeExports.jsx("h3", { children: "Your Rights (Data Subject Rights)" }), jsxRuntimeExports.jsx("p", { children: "You have the following rights under the GDPR: Right to Information (Art. 15), Right to Rectification (Art. 16), Right to Erasure (Art. 17) and Restriction of Processing (Art. 18), Right to Data Portability (Art. 20), Right to Objection to processing based on legitimate interests (Art. 21), and Right to Complain to a supervisory authority (Art. 77)." }), jsxRuntimeExports.jsx("p", { children: "Note: Without clear identification features, the operator may not be able to assign individual chat histories to a person. For inquiries, please contact the operator of this website/application." })] })] }) }));
|
|
46997
|
+
};
|
|
46998
|
+
|
|
45862
46999
|
const MenuIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "4", y1: "10", x2: "20", y2: "10" }), jsxRuntimeExports.jsx("line", { x1: "10", y1: "14", x2: "20", y2: "14" })] }));
|
|
45863
47000
|
const PlusIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), jsxRuntimeExports.jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
|
|
45864
47001
|
const TrashIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M3 6h18" }), jsxRuntimeExports.jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), jsxRuntimeExports.jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })] }));
|
|
45865
47002
|
const CloseIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntimeExports.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
|
|
45866
|
-
const
|
|
47003
|
+
const BackIcon = () => (jsxRuntimeExports.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("path", { d: "M19 12H5" }), jsxRuntimeExports.jsx("path", { d: "M12 19l-7-7 7-7" })] }));
|
|
47004
|
+
const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick, onActionDismiss,
|
|
45867
47005
|
// Chat history props (only active when persistConversation is true)
|
|
45868
47006
|
conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
|
|
45869
47007
|
// Override props for live preview
|
|
@@ -45880,6 +47018,8 @@
|
|
|
45880
47018
|
const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
|
|
45881
47019
|
// Track if history panel is open
|
|
45882
47020
|
const [showHistory, setShowHistory] = reactExports.useState(false);
|
|
47021
|
+
// Track if data policy view is open
|
|
47022
|
+
const [showDataPolicy, setShowDataPolicy] = reactExports.useState(false);
|
|
45883
47023
|
// Scroll button state (managed by MessageList)
|
|
45884
47024
|
const [showScrollButton, setShowScrollButton] = reactExports.useState(false);
|
|
45885
47025
|
const [scrollToBottom, setScrollToBottom] = reactExports.useState(null);
|
|
@@ -45889,6 +47029,13 @@
|
|
|
45889
47029
|
}, []);
|
|
45890
47030
|
// History exit animation when starting a new chat from overview
|
|
45891
47031
|
const [isHistoryExiting, setIsHistoryExiting] = reactExports.useState(false);
|
|
47032
|
+
// Handle data policy click
|
|
47033
|
+
const handleDataPolicyClick = reactExports.useCallback(() => {
|
|
47034
|
+
setShowDataPolicy(true);
|
|
47035
|
+
}, []);
|
|
47036
|
+
const handleDataPolicyBack = reactExports.useCallback(() => {
|
|
47037
|
+
setShowDataPolicy(false);
|
|
47038
|
+
}, []);
|
|
45892
47039
|
// Load conversations when history panel opens
|
|
45893
47040
|
const handleOpenHistory = () => {
|
|
45894
47041
|
setShowHistory(true);
|
|
@@ -45936,10 +47083,22 @@
|
|
|
45936
47083
|
// The backend will detect and trigger the action based on the message
|
|
45937
47084
|
onSendMessage(question);
|
|
45938
47085
|
};
|
|
45939
|
-
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntimeExports.jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''}`, children: showHistory ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: headerTitle }), jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsxRuntimeExports.jsx(PlusIcon, {}) })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsxRuntimeExports.jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsxRuntimeExports.jsx(MenuIcon, {}) })), jsxRuntimeExports.jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsxRuntimeExports.jsx(CloseIcon, {}) })] })] })) }),
|
|
47086
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsxRuntimeExports.jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsxRuntimeExports.jsx(BackIcon, {}) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: "Privacy Notice" })] })) : showHistory ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: headerTitle }), jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsxRuntimeExports.jsx(PlusIcon, {}) })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsxRuntimeExports.jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsxRuntimeExports.jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsxRuntimeExports.jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsxRuntimeExports.jsx(MenuIcon, {}) })), jsxRuntimeExports.jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsxRuntimeExports.jsx(CloseIcon, {}) })] })] })) }), showDataPolicy ? (jsxRuntimeExports.jsx(DataPolicyView, { config: config, onBack: handleDataPolicyBack, widgetName: headerTitle })) : showHistory ? (
|
|
47087
|
+
/* History Panel */
|
|
47088
|
+
jsxRuntimeExports.jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsxRuntimeExports.jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsxRuntimeExports.jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsxRuntimeExports.jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxRuntimeExports.jsxs("div", { className: "ai-chat-history-item-content", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsxRuntimeExports.jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
|
|
45940
47089
|
e.stopPropagation();
|
|
45941
47090
|
onDeleteConversation(conv.id);
|
|
45942
|
-
}, "aria-label": "Delete conversation", children: jsxRuntimeExports.jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsxRuntimeExports.jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
47091
|
+
}, "aria-label": "Delete conversation", children: jsxRuntimeExports.jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsxRuntimeExports.jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsxRuntimeExports.jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
|
|
47092
|
+
console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
|
|
47093
|
+
messages.forEach((m, i) => {
|
|
47094
|
+
console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
|
|
47095
|
+
});
|
|
47096
|
+
console.log('[DEBUG ChatWindow] getActionRenderer available:', !!getActionRenderer);
|
|
47097
|
+
if (getActionRenderer) {
|
|
47098
|
+
console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
|
|
47099
|
+
}
|
|
47100
|
+
return null;
|
|
47101
|
+
})(), jsxRuntimeExports.jsx(MessageList, { messages: messages, isTyping: isTyping, showTypingIndicator: settings?.showTypingIndicator, showTimestamps: settings?.showTimestamps, showToolCalls: settings?.showToolCalls, enableFeedback: settings?.enableFeedback, welcomeTitle: welcomeTitle || 'Welcome Message', welcomeMessage: welcomeMessage, suggestedQuestions: suggestedQuestionsOverride ?? settings?.suggestedQuestions, accentColor: appearance?.primaryColor, onSuggestedQuestionClick: handleQuestionClick, onActionClick: onActionClick, onActionDismiss: onActionDismiss, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer }), settings?.showDataPolicy && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-page-disclaimer", children: [jsxRuntimeExports.jsx("span", { children: "AI-generated responses may be inaccurate." }), jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-page-disclaimer-link", onClick: handleDataPolicyClick, children: "Privacy Notice" })] })), jsxRuntimeExports.jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), jsxRuntimeExports.jsx(MessageInput, { onSend: onSendMessage, placeholder: isLimitReached ? 'Message limit reached' : (isTyping ? 'Waiting for response...' : inputPlaceholder), disabled: isLoading || isTyping || isLimitReached, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] }))] }));
|
|
45943
47102
|
};
|
|
45944
47103
|
|
|
45945
47104
|
/**
|
|
@@ -46345,7 +47504,7 @@
|
|
|
46345
47504
|
if ( ref === void 0 ) ref = {};
|
|
46346
47505
|
var insertAt = ref.insertAt;
|
|
46347
47506
|
|
|
46348
|
-
if (typeof document === 'undefined') { return; }
|
|
47507
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
46349
47508
|
|
|
46350
47509
|
var head = document.head || document.getElementsByTagName('head')[0];
|
|
46351
47510
|
var style = document.createElement('style');
|
|
@@ -46368,7 +47527,10 @@
|
|
|
46368
47527
|
}
|
|
46369
47528
|
}
|
|
46370
47529
|
|
|
46371
|
-
var css_248z = ".ai-chat-message{animation:ai-chat-message-appear .2s var(--chat-ease-bounce);max-width:85%}.ai-chat-message-content{border-radius:var(--chat-radius-bubble,14px);font-size:var(--chat-text-md,15px);line-height:var(--chat-line-relaxed,1.6);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-message.user .ai-chat-message-content{background:var(--chat-user-bg,#f4f3f0);border-bottom-right-radius:var(--chat-radius-sm,4px);color:var(--chat-user-text,#000)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--chat-assistant-bg,transparent);color:var(--chat-assistant-text,#000)}.ai-chat-message-timestamp{color:var(--chat-text-muted,#71717a);font-size:var(--chat-text-xs,12px);margin-top:var(--chat-space-xs,4px);padding:0 var(--chat-space-xs,4px)}.ai-chat-message.streaming .ai-chat-message-content:after{animation:ai-chat-cursor-blink .8s infinite;content:\"▋\";margin-left:2px;opacity:.7}@keyframes ai-chat-message-appear{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-cursor-blink{0%,50%{opacity:1}51%,to{opacity:0}}.ai-chat-message.fullpage .ai-chat-message-content{font-size:var(--chat-text-lg,18px);padding:var(--chat-space-md,16px) var(--chat-space-lg,24px)}.ai-chat-typing{gap:var(--chat-space-xs,4px);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-typing-dot{background:var(--chat-text-muted,#71717a)}.ai-chat-tool-gear{color:var(--text-primary,#3e3e3e)}.ai-chat-tool-gear.spinning{animation:ai-chat-spin 1.5s linear infinite}.ai-chat-tool-badge{border-radius:8px}.ai-chat-tool-badge.loading{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-tool-badge.error{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-tool-check{color:#22c55e;flex-shrink:0}.ai-chat-tool-error{color:#ef4444;flex-shrink:0}.ai-chat-tool-badge .tool-name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear{color:#fff}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-badge.error,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge.error,.dark .ai-chat-tool-badge.error,[data-theme=dark] .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.chakra-ui-dark .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.chakra-ui-dark .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.chakra-ui-dark .ai-chat-tool-badge.error,html.dark .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}@keyframes ai-chat-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.ai-chat-action-skeleton-item{animation:ai-chat-skeleton-pulse 1.5s ease-in-out infinite;background:var(--bg-secondary,#e5e7eb)}.ai-chat-widget.dark .ai-chat-action-skeleton-item,.chakra-ui-dark .ai-chat-action-skeleton-item,.dark .ai-chat-action-skeleton-item,[data-theme=dark] .ai-chat-action-skeleton-item{background:hsla(0,0%,100%,.1)}.ai-chat-action-skeleton-content{display:flex;flex-direction:column;gap:16px}.ai-chat-action-skeleton-header{align-items:center;display:flex;gap:10px}.ai-chat-action-skeleton-box{background:rgba(0,0,0,.08);border-radius:10px;display:flex;flex-direction:column;gap:8px;padding:14px}.ai-chat-widget.dark .ai-chat-action-skeleton-box,.chakra-ui-dark .ai-chat-action-skeleton-box,.dark .ai-chat-action-skeleton-box,[data-theme=dark] .ai-chat-action-skeleton-box{background:rgba(0,0,0,.25)}.ai-chat-action-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:none;border-radius:var(--radius-lg,12px);box-sizing:border-box;margin-top:var(--space-sm,8px);max-width:100%;padding:var(--space-md,16px);transition:all var(--duration-normal,.25s) ease;width:100%}.ai-chat-widget.dark .ai-chat-action-card,.chakra-ui-dark .ai-chat-action-card,.dark .ai-chat-action-card,[data-theme=dark] .ai-chat-action-card{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-booked{background:var(--bg-secondary,#f4f4f4);border:none}.ai-chat-widget.dark .ai-chat-action-booked,.chakra-ui-dark .ai-chat-action-booked,.dark .ai-chat-action-booked,[data-theme=dark] .ai-chat-action-booked{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-header{align-items:center;color:var(--text-primary,#3e3e3e);display:flex;font-size:var(--text-md,15px);font-weight:var(--font-weight-semibold,600);gap:var(--space-sm,8px);margin-bottom:var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-action-header,.chakra-ui-dark .ai-chat-action-header,.dark .ai-chat-action-header,[data-theme=dark] .ai-chat-action-header{color:var(--text-primary,#fff)}.ai-chat-action-icon{color:var(--action-accent,var(--primary-color,#3b82f6));flex-shrink:0;height:20px;width:20px}.ai-chat-action-success-icon-wrapper{align-items:center;background:var(--action-accent,var(--primary-color,#22c55e));border-radius:50%;color:#fff;display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ai-chat-action-icon-success{color:currentColor;height:14px;width:14px}.ai-chat-action-detail-box{background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;flex-direction:column;gap:4px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-action-detail-box,.chakra-ui-dark .ai-chat-action-detail-box,.dark .ai-chat-action-detail-box,[data-theme=dark] .ai-chat-action-detail-box{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.05)}.ai-chat-action-label-small{color:var(--text-muted,#71717a);font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-action-value-large{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:500}.ai-chat-widget.dark .ai-chat-action-value-large,.chakra-ui-dark .ai-chat-action-value-large,.dark .ai-chat-action-value-large,[data-theme=dark] .ai-chat-action-value-large{color:#fff}.ai-chat-action-link-button{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;box-sizing:border-box;color:#fff;display:flex;font-size:14px;font-weight:600;gap:6px;justify-content:center;margin-top:8px;padding:12px;text-decoration:none;transition:all .2s ease;width:100%}.ai-chat-action-link-button:hover{opacity:.9;transform:translateY(-1px)}.ai-chat-action-body{display:flex;flex-direction:column;gap:var(--space-md,16px)}.ai-chat-action-field{display:flex;flex-direction:column;gap:var(--space-xs,6px)}.ai-chat-action-label{color:var(--text-secondary,#6b7280);font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500)}.ai-chat-widget.dark .ai-chat-action-label,.chakra-ui-dark .ai-chat-action-label,.dark .ai-chat-action-label,[data-theme=dark] .ai-chat-action-label{color:var(--text-secondary,#a1a1aa)}.ai-chat-action-input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);font-size:var(--text-sm,13px);outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease}.ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-action-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-action-input,.chakra-ui-dark .ai-chat-action-input,.dark .ai-chat-action-input,[data-theme=dark] .ai-chat-action-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-input:focus,.chakra-ui-dark .ai-chat-action-input:focus,.dark .ai-chat-action-input:focus,[data-theme=dark] .ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-date-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(90px,1fr))}.ai-chat-action-date-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-date-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn,.chakra-ui-dark .ai-chat-action-date-btn,.dark .ai-chat-action-date-btn,[data-theme=dark] .ai-chat-action-date-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn:hover,.chakra-ui-dark .ai-chat-action-date-btn:hover,.dark .ai-chat-action-date-btn:hover,[data-theme=dark] .ai-chat-action-date-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-date-btn.active,.chakra-ui-dark .ai-chat-action-date-btn.active,.dark .ai-chat-action-date-btn.active,[data-theme=dark] .ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-time-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}.ai-chat-action-time-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-time-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn,.chakra-ui-dark .ai-chat-action-time-btn,.dark .ai-chat-action-time-btn,[data-theme=dark] .ai-chat-action-time-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn:hover,.chakra-ui-dark .ai-chat-action-time-btn:hover,.dark .ai-chat-action-time-btn:hover,[data-theme=dark] .ai-chat-action-time-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-time-btn.active,.chakra-ui-dark .ai-chat-action-time-btn.active,.dark .ai-chat-action-time-btn.active,[data-theme=dark] .ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-button{background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;color:#fff;cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-semibold,600);padding:12px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-action-error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-error,.chakra-ui-dark .ai-chat-action-error,.dark .ai-chat-action-error,[data-theme=dark] .ai-chat-action-error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-action-hint{color:var(--text-muted,#9ca3af);font-size:var(--text-sm,13px);padding:var(--space-sm,8px);text-align:center}.ai-chat-link-preview{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);cursor:pointer;display:flex;flex-direction:column;margin-top:var(--space-sm,8px);overflow:hidden;position:relative;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 8px rgba(0,0,0,.1);transform:translateY(-1px)}.ai-chat-link-preview:focus{border-color:var(--action-accent);box-shadow:0 0 0 2px rgba(59,130,246,.2);outline:none}.ai-chat-widget.dark .ai-chat-link-preview,.chakra-ui-dark .ai-chat-link-preview,.dark .ai-chat-link-preview,[data-theme=dark] .ai-chat-link-preview{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-widget.dark .ai-chat-link-preview:hover,.chakra-ui-dark .ai-chat-link-preview:hover,.dark .ai-chat-link-preview:hover,[data-theme=dark] .ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 12px rgba(0,0,0,.3)}.ai-chat-link-preview__image{aspect-ratio:1.91/1;background:var(--bg-muted,#e5e7eb);overflow:hidden;width:100%}.ai-chat-widget.dark .ai-chat-link-preview__image,.chakra-ui-dark .ai-chat-link-preview__image,.dark .ai-chat-link-preview__image,[data-theme=dark] .ai-chat-link-preview__image{background:hsla(0,0%,100%,.05)}.ai-chat-link-preview__image img{height:100%;object-fit:cover;width:100%}.ai-chat-link-preview__content{flex:1;padding:12px}.ai-chat-link-preview__site{align-items:center;display:flex;gap:6px;margin-bottom:6px}.ai-chat-link-preview__favicon{border-radius:2px;flex-shrink:0;height:16px;width:16px}.ai-chat-link-preview__domain{color:var(--text-muted,#71717a);font-size:12px;letter-spacing:.5px;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;white-space:nowrap}.ai-chat-link-preview__title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-primary,#3e3e3e);display:-webkit-box;font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px;overflow:hidden}.ai-chat-widget.dark .ai-chat-link-preview__title,.chakra-ui-dark .ai-chat-link-preview__title,.dark .ai-chat-link-preview__title,[data-theme=dark] .ai-chat-link-preview__title{color:#fff}.ai-chat-link-preview__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#71717a);display:-webkit-box;font-size:13px;line-height:1.4;margin:0;overflow:hidden}.ai-chat-link-preview__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:8px 0 0;padding-top:8px}.ai-chat-widget.dark .ai-chat-link-preview__context,.chakra-ui-dark .ai-chat-link-preview__context,.dark .ai-chat-link-preview__context,[data-theme=dark] .ai-chat-link-preview__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-link-preview__arrow{align-items:center;background:var(--bg-primary,#fff);border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.1);color:var(--text-muted,#71717a);display:flex;height:28px;justify-content:center;opacity:0;position:absolute;right:12px;top:12px;transition:opacity .2s,background .2s;width:28px}.ai-chat-link-preview:hover .ai-chat-link-preview__arrow{opacity:1}.ai-chat-widget.dark .ai-chat-link-preview__arrow,.chakra-ui-dark .ai-chat-link-preview__arrow,.dark .ai-chat-link-preview__arrow,[data-theme=dark] .ai-chat-link-preview__arrow{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-link-preview--error{border-color:rgba(239,68,68,.3)}.ai-chat-link-preview--error:hover{border-color:rgba(239,68,68,.5)}.ai-chat-link-preview__error-text{color:#dc2626;font-size:12px;margin:4px 0 0}.ai-chat-widget.dark .ai-chat-link-preview__error-text,.chakra-ui-dark .ai-chat-link-preview__error-text,.dark .ai-chat-link-preview__error-text,[data-theme=dark] .ai-chat-link-preview__error-text{color:#fca5a5}.ai-chat-video-player{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;margin-top:var(--space-sm,8px);overflow:hidden}.ai-chat-widget.dark .ai-chat-video-player,.chakra-ui-dark .ai-chat-video-player,.dark .ai-chat-video-player,[data-theme=dark] .ai-chat-video-player{background:var(--bg-secondary,#3a3a3a)}.ai-chat-video-player__header{align-items:center;color:var(--action-accent,var(--primary-color,#3b82f6));display:flex;gap:8px;padding:12px 12px 8px}.ai-chat-video-player__title{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600}.ai-chat-widget.dark .ai-chat-video-player__title,.chakra-ui-dark .ai-chat-video-player__title,.dark .ai-chat-video-player__title,[data-theme=dark] .ai-chat-video-player__title{color:#fff}.ai-chat-video-player__container{aspect-ratio:16/9;background:#000;position:relative;width:100%}.ai-chat-video-player__thumbnail{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-video-player__thumbnail img{height:100%;object-fit:cover;width:100%}.ai-chat-video-player__placeholder{align-items:center;background:linear-gradient(135deg,#1a1a2e,#16213e);cursor:pointer;display:flex;flex-direction:column;gap:8px;height:100%;justify-content:center;position:relative;width:100%}.ai-chat-video-player__click-text{color:hsla(0,0%,100%,.7);font-size:13px}.ai-chat-video-player__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:64px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:64px}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn{left:auto;position:relative;top:auto;transform:none}.ai-chat-video-player__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn:hover{transform:scale(1.05)}.ai-chat-video-player__provider-badge{background:rgba(0,0,0,.8);border-radius:4px;bottom:8px;color:#fff;font-size:11px;font-weight:600;letter-spacing:.5px;padding:4px 8px;position:absolute;right:8px;text-transform:uppercase}.ai-chat-video-player__iframe,.ai-chat-video-player__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-video-player__error{align-items:center;background:rgba(239,68,68,.1);color:#dc2626;display:flex;font-size:13px;height:100%;justify-content:center;padding:16px;text-align:center;width:100%}.ai-chat-widget.dark .ai-chat-video-player__error,.chakra-ui-dark .ai-chat-video-player__error,.dark .ai-chat-video-player__error,[data-theme=dark] .ai-chat-video-player__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-video-player__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;padding:10px 12px}.ai-chat-widget.dark .ai-chat-video-player__context,.chakra-ui-dark .ai-chat-video-player__context,.dark .ai-chat-video-player__context,[data-theme=dark] .ai-chat-video-player__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-location-card{background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:12px;overflow:hidden}.ai-chat-widget.dark .ai-chat-location-card,.chakra-ui-dark .ai-chat-location-card,.dark .ai-chat-location-card,[data-theme=dark] .ai-chat-location-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-location-card--compact{border-radius:10px}.ai-chat-location-card--error{color:var(--text-muted,#71717a);padding:16px;text-align:center}.ai-chat-location-card__map{background:var(--bg-muted,#f4f4f5);position:relative;width:100%}.ai-chat-widget.dark .ai-chat-location-card__map,.chakra-ui-dark .ai-chat-location-card__map,.dark .ai-chat-location-card__map,[data-theme=dark] .ai-chat-location-card__map{background:rgba(0,0,0,.2)}.ai-chat-location-card__map iframe{border:none;display:block;height:100%;width:100%}.ai-chat-location-card__content{padding:14px}.ai-chat-location-card--compact .ai-chat-location-card__content{padding:12px}.ai-chat-location-card__header{align-items:center;display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.ai-chat-location-card__name{color:var(--text-primary,#18181b);flex:1;font-size:16px;font-weight:600;margin:0;min-width:0}.ai-chat-widget.dark .ai-chat-location-card__name,.chakra-ui-dark .ai-chat-location-card__name,.dark .ai-chat-location-card__name,[data-theme=dark] .ai-chat-location-card__name{color:#fff}.ai-chat-location-card--compact .ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__type{background:var(--bg-muted,#f4f4f5);border-radius:10px;color:var(--text-muted,#71717a);font-size:11px;font-weight:500;letter-spacing:.5px;padding:2px 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-location-card__type,.chakra-ui-dark .ai-chat-location-card__type,.dark .ai-chat-location-card__type,[data-theme=dark] .ai-chat-location-card__type{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}.ai-chat-location-card__status{border-radius:12px;font-size:12px;font-weight:500;padding:2px 8px}.ai-chat-location-card__status--open{background:#dcfce7;color:#16a34a}.ai-chat-location-card__status--closed{background:#fef2f2;color:#dc2626}.ai-chat-widget.dark .ai-chat-location-card__status--open,.chakra-ui-dark .ai-chat-location-card__status--open,.dark .ai-chat-location-card__status--open,[data-theme=dark] .ai-chat-location-card__status--open{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-widget.dark .ai-chat-location-card__status--closed,.chakra-ui-dark .ai-chat-location-card__status--closed,.dark .ai-chat-location-card__status--closed,[data-theme=dark] .ai-chat-location-card__status--closed{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-location-card__address{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__address svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__hours{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;margin-bottom:8px}.ai-chat-location-card__hours svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__hours-list{flex:1}.ai-chat-location-card__hours-toggle{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;font:inherit;gap:4px;padding:0}.ai-chat-location-card__hours-toggle:hover{text-decoration:underline}.ai-chat-location-card__hours-full{list-style:none;margin:8px 0 0;padding:0}.ai-chat-location-card__hours-full li{display:flex;font-size:12px;justify-content:space-between;padding:4px 0}.ai-chat-location-card__hours-today{color:var(--text-primary,#18181b);font-weight:600}.ai-chat-widget.dark .ai-chat-location-card__hours-today,.chakra-ui-dark .ai-chat-location-card__hours-today,.dark .ai-chat-location-card__hours-today,[data-theme=dark] .ai-chat-location-card__hours-today{color:#fff}.ai-chat-location-card__phone{align-items:center;background:none;border:none;color:var(--action-accent,#3b82f6);cursor:pointer;display:flex;font-size:13px;gap:6px;margin-bottom:12px;padding:0}.ai-chat-location-card__phone:hover{text-decoration:underline}.ai-chat-location-card__actions{display:flex;gap:8px;justify-content:flex-start;width:100%}.ai-chat-location-card__button{align-items:center;background:var(--action-accent,#3b82f6);border:none;border-radius:20px;color:#fff;cursor:pointer;display:flex;flex:1;font-size:13px;font-weight:500;gap:6px;justify-content:center;padding:10px 16px;transition:opacity .2s}.ai-chat-location-card__button:hover{opacity:.9}.ai-chat-location-card--compact .ai-chat-location-card__button{font-size:12px;padding:8px 12px}.ai-chat-location-card__link{align-items:center;background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:20px;color:var(--text-primary,#18181b);display:flex;font-size:13px;gap:6px;padding:10px 16px;text-decoration:none;transition:border-color .2s}.ai-chat-widget.dark .ai-chat-location-card__link,.chakra-ui-dark .ai-chat-location-card__link,.dark .ai-chat-location-card__link,[data-theme=dark] .ai-chat-location-card__link{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-location-card__link:hover{border-color:var(--action-accent,#3b82f6)}.ai-chat-location-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-location-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:4px;padding:0 4px}.ai-chat-location-card-list__stack{display:grid;gap:12px;grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:1200px){.ai-chat-location-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:768px){.ai-chat-location-card-list__stack{grid-template-columns:1fr}}@media (max-width:520px){.ai-chat-location-card-list__stack{grid-template-columns:1fr!important}}@media (min-width:521px) and (max-width:900px){.ai-chat-location-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))!important}}.ai-chat-location-card-list__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:400px){.ai-chat-location-card-list__grid{grid-template-columns:1fr}}.ai-chat-location-card-list__carousel{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-snap-type:x mandatory;scrollbar-width:none}.ai-chat-location-card-list__carousel::-webkit-scrollbar{display:none}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 280px;scroll-snap-align:start}.ai-chat-widget,.chat-ui{--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:8px;--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,.chat-ui.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,.chat-ui{-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 ai-chat-window-open{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes ai-chat-window-close{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes ai-chat-message-slide-in{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-welcome-fade-in{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-typing-pulse{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 ai-chat-feedback-morph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes ai-chat-checkmark-pop{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)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}@media (max-width:480px){.ai-chat-widget-container.is-open{height:100vh!important;inset:0!important;width:100vw!important}.ai-chat-widget-container.is-open .ai-chat-window{animation:none!important;border-radius:0!important;height:100%!important;inset:0!important;max-height:100%!important;max-width:100%!important;position:absolute!important;width:100%!important}.ai-chat-widget-container.is-open .ai-chat-button{display:none!important;visibility:hidden!important}.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-window{animation:ai-chat-window-open var(--duration-slow,.35s) var(--spring-bounce);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:ai-chat-window-close var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:500px;width:380px}.ai-chat-window.size-medium,.ai-chat-window.size-small{max-height:calc(100vh - 100px);max-width:calc(100vw - 40px)}.ai-chat-window.size-medium{height:600px;width:420px}.ai-chat-window.size-large{height:700px;max-height:calc(100vh - 100px);max-width:calc(100vw - 40px);width:480px}.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,.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:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover,.ai-chat-header-button:hover{color:var(--text-primary)}.ai-chat-close-button:active,.ai-chat-header-button:active{transform:scale(.95)}.ai-chat-close-button svg,.ai-chat-header-button svg{height:22px;width:22px}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--border-default,#d3d3d3);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:opacity var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{opacity:.9}.ai-chat-button:active{opacity:.8}.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-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:flex-end;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);box-sizing:border-box;display:flex;gap:0;height:52px;overflow:hidden;padding:6px 6px 6px 16px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-input-wrapper.multiline{border-radius:14px!important;min-height:64px;padding:10px 10px 10px 14px}.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{word-wrap:break-word!important;background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;box-sizing:border-box!important;color:var(--input-text,#000)!important;flex:1!important;font-family:inherit!important;font-size:var(--text-md,15px)!important;height:40px!important;line-height:20px!important;margin:0!important;max-height:40px!important;min-height:40px!important;min-width:0!important;outline:none!important;overflow-wrap:anywhere!important;overflow-x:hidden!important;overflow-y:auto!important;padding:10px var(--space-sm,8px)!important;resize:none!important;white-space:pre-wrap!important;width:0!important;word-break:break-word!important}.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;align-self: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;align-self: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;min-height:40px;min-width:40px;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-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:ai-chat-message-slide-in .2s var(--spring-bounce);display:flex;flex-direction:column;max-width:90%}.ai-chat-message.user{align-items:flex-end;align-self:flex-end}.ai-chat-message.assistant{align-items:flex-start;align-self:flex-start;max-width:100%}.ai-chat-message.tool{align-self:flex-start;margin:0 -16px;max-width:100%;padding:0;width:calc(100% + 32px)}.ai-chat-message-content{word-wrap:break-word;border-radius:18px;font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);overflow-wrap:break-word;padding:8px 14px}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border-radius:18px;color:var(--user-text,#000)}.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.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);color:var(--agent-text,#000);padding:0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fff)}.ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:var(--text-xs,12px);margin-top:var(--space-xs,4px);padding:0 var(--space-xs,4px)}.ai-chat-welcome{animation:ai-chat-welcome-fade-in .3s var(--spring-smooth);display:flex;flex-direction:column;gap:var(--space-md,16px);padding:var(--space-lg,24px) 0}.ai-chat-welcome-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-2xl,28px);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3)}.ai-chat-widget.dark .ai-chat-welcome-title{color:var(--text-primary,#fff)}.ai-chat-welcome-text{color:var(--text-secondary,#000);font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);max-width:100%}.ai-chat-widget.dark .ai-chat-welcome-text{color:var(--text-secondary,#fff)}.ai-chat-typing{align-items:center;display:flex;gap:var(--space-xs,4px);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-typing-dot{animation:ai-chat-typing-bounce 1.4s ease-in-out infinite both;background:var(--text-muted,#71717a);border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:first-child{animation-delay:-.32s}.ai-chat-typing-dot:nth-child(2){animation-delay:-.16s}.ai-chat-typing-dot:nth-child(3){animation-delay:0s}@keyframes ai-chat-typing-bounce{0%,80%,to{opacity:.4;transform:scale(.6)}40%{opacity:1;transform:scale(1)}}.ai-chat-scroll-button{align-items:center;background:var(--bg-secondary,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:50%;bottom:80px;box-shadow:0 2px 8px rgba(0,0,0,.1);color:var(--text-secondary,#71717a);cursor:pointer;display:flex;height:36px;justify-content:center;left:50%;opacity:0;pointer-events:none;position:absolute;transform:translateX(-50%);transition:background .15s ease,box-shadow .15s ease,opacity .15s ease,visibility .15s ease;visibility:hidden;width:36px;z-index:15}.ai-chat-scroll-button.visible{opacity:1;pointer-events:auto;visibility:visible}.ai-chat-scroll-button:hover{background:var(--bg-tertiary,#e4e4e7);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ai-chat-scroll-button:active{background:var(--bg-tertiary,#d4d4d8)}.ai-chat-widget.dark .ai-chat-scroll-button{background:var(--bg-secondary,#3f3f46);border-color:var(--border-subtle,hsla(0,0%,100%,.1));box-shadow:0 2px 8px rgba(0,0,0,.3);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-scroll-button:hover{background:var(--bg-tertiary,#52525b);box-shadow:0 4px 12px rgba(0,0,0,.4)}.ai-chat-error{background:var(--bg-secondary);border-radius:var(--radius-chat-bubble);color:var(--text-primary);font-size:var(--text-md);margin:0 auto;padding:10px var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 var(--space-sm) 0}.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:var(--space-sm) 0;padding-left:var(--space-lg)}.ai-chat-message.assistant .ai-chat-message-content li{margin-bottom:var(--space-xs)}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.05);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,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,.05);border-radius:var(--radius-md);margin:var(--space-sm) 0;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%,.05)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;padding:0}.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 strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--border-default);color:var(--text-muted);margin:var(--space-sm) 0;padding-left:var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle,rgba(0,0,0,.1));margin:var(--space-lg,24px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content hr{border-top-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content table{border-collapse:collapse;font-size:var(--text-sm);margin:var(--space-sm) 0;width:100%}.ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-message.assistant .ai-chat-message-content th{border:1px solid var(--border-subtle);padding:var(--space-sm);text-align:left}.ai-chat-message.assistant .ai-chat-message-content th{font-weight:var(--font-weight-semibold);white-space:nowrap}.ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:rgba(0,0,0,.02)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:hsla(0,0%,100%,.03)}.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{align-items:center;background:transparent;border:1px solid var(--border-default,#d4d4d8);border-radius:var(--radius-preset-badge,18px);color:var(--text-primary,#18181b);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,border-color .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:transparent;border-color:var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{background:var(--bg-hover,#f4f4f5);border-color:var(--border-default,#d4d4d8)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{background:var(--bg-hover,#3f3f46);border-color:var(--border-subtle,#52525b)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question.action-type{border:none}.ai-chat-suggested-question.action-type,.ai-chat-widget.dark .ai-chat-suggested-question.action-type{background:var(--primary-color,var(--button-color,#ef4444));color:var(--button-icon-color,#fff)}.ai-chat-suggested-question.action-type:hover{background:var(--primary-color,var(--button-color,#ef4444));opacity:.9}.ai-chat-suggested-question-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-suggested-question:not(.action-type) .ai-chat-suggested-question-icon{display:none}.ai-chat-follow-up-suggestions{box-sizing:border-box;margin:0;padding:8px 16px 0;width:100%}.ai-chat-follow-up-list{align-items:flex-end;display:flex;flex-direction:column;gap:6px}.ai-chat-follow-up-item{align-items:center;border:none;border-radius:var(--radius-preset-badge,18px);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:opacity .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-follow-up-item,.ai-chat-widget.dark .ai-chat-follow-up-item{background:var(--primary-color,var(--button-color,#07f));color:var(--button-icon-color,#fff)}.ai-chat-follow-up-item:hover{opacity:.9}.ai-chat-follow-up-item:active{transform:scale(.98)}.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type,.dark .ai-chat-follow-up-item.question-type,[data-theme=dark] .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}}.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5);opacity:1}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type:hover,.dark .ai-chat-follow-up-item.question-type:hover,[data-theme=dark] .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}}.ai-chat-follow-up-item.action-type{background:var(--primary-color,var(--button-color,#07f));border:none;color:var(--button-icon-color,#fff)}.ai-chat-follow-up-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-follow-up-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.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:ai-chat-feedback-morph .3s var(--spring-bounce);gap:var(--space-xs)}.ai-chat-feedback-message{align-items:center;display:flex;gap:4px;margin-left:var(--space-xxs)}.ai-chat-feedback-checkmark{animation:ai-chat-checkmark-pop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-xs);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-xs) 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:center;background:var(--user-bg,#f4f4f5);border-radius:var(--radius-history-item,15px);display:flex;flex:0 0 auto;flex-direction:row;height:var(--history-item-height,36px);margin:0;overflow:hidden;transition:background var(--duration-fast,.15s) ease;width:100%}.ai-chat-history-item-content{align-items:center;background:transparent;border:none;cursor:pointer;display:flex;flex:1;flex-direction:row;height:100%;min-width:0;padding:0 var(--space-xs,4px) 0 var(--space-md,16px);text-align:left}.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);flex:1;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-history-item-delete{align-items:center;background:transparent;border:none;border-radius:var(--radius-sm,6px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-left:auto;margin-right:var(--space-xs,4px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:24px}.ai-chat-history-item-delete svg{height:14px;width:14px}.ai-chat-history-item:hover .ai-chat-history-item-delete{opacity:1}.ai-chat-history-item-delete:hover{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0;padding:0 16px}.ai-chat-tool-gear{color:#1f2937;flex-shrink:0;height:20px;width:20px}.ai-chat-tool-gear.spinning{animation:ai-chat-gear-spin 1.5s linear infinite}.ai-chat-tool-badges{align-items:center;display:flex;flex-wrap:wrap;gap:8px}.ai-chat-tool-badge{align-items:center;background:#e5e7eb;border:1px solid #d1d5db;border-radius:var(--radius-action-badge,8px);color:#1f2937;display:inline-flex;font-size:12px;font-weight:500;gap:4px;line-height:1.2;padding:5px 12px;transition:all .2s ease;white-space:nowrap}.ai-chat-tool-badge.loading{animation:ai-chat-tool-gradient 2s linear infinite;background:linear-gradient(90deg,var(--tool-loading-bg-1,#e0e0e0) 0,var(--tool-loading-bg-2,#f0f0f0) 25%,var(--tool-loading-bg-3,#fff) 50%,var(--tool-loading-bg-2,#f0f0f0) 75%,var(--tool-loading-bg-1,#e0e0e0) 100%);background-size:200% 100%;color:var(--tool-loading-text,#1a1a1a);position:relative}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.loading{--tool-loading-bg-1:#2a2a2a;--tool-loading-bg-2:#3a3a3a;--tool-loading-bg-3:#4a4a4a;--tool-loading-text:#fff}.ai-chat-tool-badge.completed{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.chakra-ui-dark .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.chakra-ui-dark .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.ai-chat-tool-badge.error{background:var(--tool-error-bg,rgba(239,68,68,.15));color:var(--tool-error-text,#ef4444)}.ai-chat-tool-badge .ai-chat-tool-check{color:#fff;flex-shrink:0}.ai-chat-tool-badge .ai-chat-tool-error{color:#ef4444;flex-shrink:0}.tool-name{font-weight:500;line-height:1.2;white-space:nowrap}.ai-chat-tool-action{box-sizing:border-box;padding:0 16px;width:100%}";
|
|
47530
|
+
var css_248z$1 = ".ai-chat-message{animation:ai-chat-message-appear .2s var(--chat-ease-bounce);max-width:85%}.ai-chat-message-content{border-radius:var(--chat-radius-bubble,14px);font-size:var(--chat-text-md,15px);line-height:var(--chat-line-relaxed,1.6);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-message.user .ai-chat-message-content{background:var(--chat-user-bg,#f4f3f0);border-bottom-right-radius:var(--chat-radius-sm,4px);color:var(--chat-user-text,#000)}.ai-chat-message.assistant .ai-chat-message-content{background:var(--chat-assistant-bg,transparent);color:var(--chat-assistant-text,#000)}.ai-chat-message-timestamp{color:var(--chat-text-muted,#71717a);font-size:var(--chat-text-xs,12px);margin-top:var(--chat-space-xs,4px);padding:0 var(--chat-space-xs,4px)}.ai-chat-message.streaming .ai-chat-message-content:after{animation:ai-chat-cursor-blink .8s infinite;content:\"▋\";margin-left:2px;opacity:.7}@keyframes ai-chat-message-appear{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-cursor-blink{0%,50%{opacity:1}51%,to{opacity:0}}.ai-chat-message.fullpage .ai-chat-message-content{font-size:var(--chat-text-lg,18px);padding:var(--chat-space-md,16px) var(--chat-space-lg,24px)}.ai-chat-typing{gap:var(--chat-space-xs,4px);padding:var(--chat-space-sm,8px) var(--chat-space-md,16px)}.ai-chat-typing-dot{background:var(--chat-text-muted,#71717a)}.ai-chat-tool-row{padding:0 16px}.ai-chat-tool-gear{color:var(--text-primary,#3e3e3e)}.ai-chat-tool-badge{border-radius:8px}.ai-chat-tool-badge.loading{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-tool-badge.error{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-tool-check{color:#22c55e;flex-shrink:0}.ai-chat-tool-error{color:#ef4444;flex-shrink:0}.ai-chat-tool-badge .tool-name{max-width:150px;overflow:hidden;text-overflow:ellipsis}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear{color:#fff}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-badge.error,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge.error,.dark .ai-chat-tool-badge.error,[data-theme=dark] .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.chakra-ui-dark .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.chakra-ui-dark .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.chakra-ui-dark .ai-chat-tool-badge.error,html.dark .ai-chat-tool-badge.error{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-pin-input-group{align-items:center;display:flex;flex-wrap:nowrap;gap:8px;justify-content:center;margin:4px 0 8px}.ai-chat-pin-input{align-items:center;appearance:none;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary,#3e3e3e);display:inline-flex;flex:0 0 42px;font-family:inherit;font-size:18px;font-weight:600;height:46px;justify-content:center;line-height:1;max-width:42px;min-width:42px;outline:none;padding:0;text-align:center;transition:border-color .2s ease,box-shadow .2s ease;width:42px}.ai-chat-pin-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-pin-input:disabled{cursor:not-allowed;opacity:.6}.ai-chat-widget.dark .ai-chat-pin-input,.chakra-ui-dark .ai-chat-pin-input,.dark .ai-chat-pin-input,[data-theme=dark] .ai-chat-pin-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-pin-input:focus,.chakra-ui-dark .ai-chat-pin-input:focus,.dark .ai-chat-pin-input:focus,[data-theme=dark] .ai-chat-pin-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-button-secondary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:9999px;color:var(--text-secondary,#6b7280);cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500);padding:10px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button-secondary:hover:not(:disabled){background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6));color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-button-secondary:disabled{cursor:not-allowed;opacity:.5}.ai-chat-widget.dark .ai-chat-action-button-secondary,.chakra-ui-dark .ai-chat-action-button-secondary,.dark .ai-chat-action-button-secondary,[data-theme=dark] .ai-chat-action-button-secondary{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#e5e7eb}.ai-chat-widget.dark .ai-chat-action-button-secondary:hover:not(:disabled),.chakra-ui-dark .ai-chat-action-button-secondary:hover:not(:disabled),.dark .ai-chat-action-button-secondary:hover:not(:disabled),[data-theme=dark] .ai-chat-action-button-secondary:hover:not(:disabled){background:rgba(59,130,246,.2);border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-appointment-list,.ai-chat-action-button-group{display:flex;flex-direction:column;gap:8px}.ai-chat-action-appointment-item{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;gap:12px;justify-content:space-between;padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-appointment-item,.chakra-ui-dark .ai-chat-action-appointment-item,.dark .ai-chat-action-appointment-item,[data-theme=dark] .ai-chat-action-appointment-item{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.08)}.ai-chat-action-appointment-info{display:flex;flex-direction:column;gap:2px;min-width:0}.ai-chat-action-appointment-subject{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-widget.dark .ai-chat-action-appointment-subject,.chakra-ui-dark .ai-chat-action-appointment-subject,.dark .ai-chat-action-appointment-subject,[data-theme=dark] .ai-chat-action-appointment-subject{color:#fff}.ai-chat-action-appointment-time{color:var(--text-muted,#71717a);font-size:12px}.ai-chat-action-appointment-item .ai-chat-action-button-secondary{font-size:12px;padding:6px 12px;width:auto}.ai-chat-action-error-message{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:12px}.ai-chat-widget.dark .ai-chat-action-error-message,.chakra-ui-dark .ai-chat-action-error-message,.dark .ai-chat-action-error-message,[data-theme=dark] .ai-chat-action-error-message{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-widget,.chat-ui{--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:8px;--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,.chat-ui.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,.chat-ui{-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:var(--widget-z-index,2147483647)}.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-widget-container.container-mode{position:absolute}@keyframes ai-chat-window-open{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes ai-chat-window-close{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes ai-chat-message-slide-in{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-welcome-fade-in{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes ai-chat-typing-pulse{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 ai-chat-feedback-morph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes ai-chat-checkmark-pop{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)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}.ai-chat-window{animation:ai-chat-window-open var(--duration-slow,.35s) var(--spring-bounce);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:ai-chat-window-close var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:500px;width:380px}.ai-chat-window.size-medium,.ai-chat-window.size-small{max-height:calc(100vh - 100px);max-width:calc(100vw - 40px)}.ai-chat-window.size-medium{height:600px;width:420px}.ai-chat-window.size-large{height:700px;max-height:calc(100vh - 100px);max-width:calc(100vw - 40px);width:480px}.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:12px 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,.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:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover,.ai-chat-header-button:hover{color:var(--text-primary)}.ai-chat-close-button:active,.ai-chat-header-button:active{transform:scale(.95)}.ai-chat-close-button svg,.ai-chat-header-button svg{height:22px;width:22px}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--border-default,#d3d3d3);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:transform var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{transform:scale(1.05)}.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-welcome-bubble{animation:ai-chat-bubble-fade-in .3s ease-out;background:var(--button-color,var(--btn-primary-bg,#07f));border:none;border-radius:16px;box-shadow:none;box-sizing:border-box;color:var(--button-icon-color,var(--btn-primary-text,#fff));cursor:pointer;font-size:13px;font-weight:500;line-height:1.5;max-width:min(420px,90vw);padding:12px 32px 12px 16px;position:absolute;text-align:left;white-space:normal;width:auto;z-index:0}.ai-chat-welcome-bubble-close{align-items:center;background:transparent;border:none;border-radius:50%;color:inherit;cursor:pointer;display:flex;height:20px;justify-content:center;opacity:.8;padding:0;position:absolute;right:8px;top:8px;transition:opacity .15s ease,background .15s ease;width:20px}.ai-chat-welcome-bubble-close:hover{background:hsla(0,0%,100%,.2);opacity:1}.ai-chat-welcome-bubble-close svg{height:12px;width:12px}.ai-chat-welcome-bubble-arrow{border-bottom:8px solid transparent;border-top:8px solid transparent;height:0;position:absolute;width:0}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{bottom:50%;right:calc(100% + 12px);text-align:left;transform:translateY(50%)}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{bottom:50%;left:calc(100% + 12px);text-align:left;transform:translateY(50%)}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{right:calc(100% + 12px);text-align:left;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{left:calc(100% + 12px);text-align:left;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble-arrow{border-left:8px solid var(--button-color,var(--btn-primary-bg,#07f));right:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble-arrow{border-right:8px solid var(--button-color,var(--btn-primary-bg,#07f));left:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble-arrow{border-left:8px solid var(--button-color,var(--btn-primary-bg,#07f));right:-8px;top:50%;transform:translateY(-50%)}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble-arrow{border-right:8px solid var(--button-color,var(--btn-primary-bg,#07f));left:-8px;top:50%;transform:translateY(-50%)}.ai-chat-welcome-bubble:hover{filter:brightness(1.1)}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-bottom-right}@keyframes ai-chat-bubble-fade-in-bottom-right{0%{opacity:0;transform:translateY(50%) translateX(8px)}to{opacity:1;transform:translateY(50%) translateX(0)}}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-bottom-left}@keyframes ai-chat-bubble-fade-in-bottom-left{0%{opacity:0;transform:translateY(50%) translateX(-8px)}to{opacity:1;transform:translateY(50%) translateX(0)}}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-top-right}@keyframes ai-chat-bubble-fade-in-top-right{0%{opacity:0;transform:translateY(-50%) translateX(8px)}to{opacity:1;transform:translateY(-50%) translateX(0)}}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-top-left}@keyframes ai-chat-bubble-fade-in-top-left{0%{opacity:0;transform:translateY(-50%) translateX(-8px)}to{opacity:1;transform:translateY(-50%) translateX(0)}}.ai-chat-trigger-pill{align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);background:hsla(0,0%,100%,.08);border:1px solid hsla(0,0%,100%,.15);border-radius:9999px;color:var(--text-primary,#fff);cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:8px;height:40px;justify-content:center;padding:0 20px;position:relative;transition:all .3s ease;white-space:nowrap;z-index:1}.ai-chat-trigger-pill.is-open{background:var(--button-color,var(--btn-primary-bg));border-color:var(--border-default,#d3d3d3);box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));height:56px;padding:0;width:56px}.ai-chat-trigger-pill.is-open .ai-chat-trigger-pill-icon{height:24px;width:24px}.ai-chat-trigger-pill:hover:not(.is-open){background:hsla(0,0%,100%,.12);border-color:hsla(0,0%,100%,.25)}.ai-chat-trigger-pill.is-open:hover{transform:scale(1.05)}.ai-chat-trigger-pill:active{transform:scale(.98)}.ai-chat-trigger-pill-icon{flex-shrink:0;height:16px;transition:all .3s ease;width:16px}.ai-chat-widget.light .ai-chat-trigger-pill{background:rgba(0,0,0,.04);border-color:rgba(0,0,0,.12);color:var(--text-primary,#1a1a1a)}.ai-chat-widget.light .ai-chat-trigger-pill:hover:not(.is-open){background:rgba(0,0,0,.08);border-color:rgba(0,0,0,.2)}.ai-chat-trigger-input-container{align-items:flex-end;display:flex;flex-direction:column;gap:8px}.ai-chat-widget-container.bottom-left .ai-chat-trigger-input-container,.ai-chat-widget-container.top-left .ai-chat-trigger-input-container{align-items:flex-start}.ai-chat-trigger-input-expand{align-items:center;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);background:hsla(0,0%,100%,.1);border:1px solid hsla(0,0%,100%,.15);border-radius:50%;color:hsla(0,0%,100%,.7);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all .2s ease;width:32px}.ai-chat-trigger-input-expand:hover{background:hsla(0,0%,100%,.15);color:hsla(0,0%,100%,.9);transform:translateY(-2px)}.ai-chat-trigger-input-expand:active{transform:translateY(0)}.ai-chat-trigger-input-expand svg{height:16px;width:16px}.ai-chat-widget.light .ai-chat-trigger-input-expand{background:rgba(0,0,0,.05);border:1px solid rgba(0,0,0,.1);color:rgba(0,0,0,.5)}.ai-chat-widget.light .ai-chat-trigger-input-expand:hover{background:rgba(0,0,0,.1);color:rgba(0,0,0,.7)}.ai-chat-trigger-input-wrapper{max-width:calc(100vw - 40px);position:relative;z-index:1}.ai-chat-widget-container.trigger-input-bar .ai-chat-trigger-input-wrapper{width:348px}.ai-chat-widget-container.trigger-input-bar.size-medium .ai-chat-trigger-input-wrapper{width:388px}.ai-chat-widget-container.trigger-input-bar.size-large .ai-chat-trigger-input-wrapper{width:448px}.ai-chat-trigger-input{backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);background:hsla(0,0%,100%,.08);border:1px solid hsla(0,0%,100%,.12);border-radius:var(--radius-input,62px);box-shadow:0 4px 24px rgba(0,0,0,.15);box-sizing:border-box;color:var(--input-text,#fff);font-size:var(--text-md,15px);height:52px;outline:none;padding:6px 52px 6px 16px;transition:all .2s ease;width:100%}.ai-chat-trigger-input::placeholder{color:var(--text-placeholder,hsla(0,0%,100%,.5))}.ai-chat-trigger-input:focus{background:hsla(0,0%,100%,.12);border-color:hsla(0,0%,100%,.25)}.ai-chat-trigger-input-btn{align-items:center;background:var(--primary-color,var(--button-color,#07f));border:none;border-radius:50%;box-shadow:0 2px 8px rgba(0,119,255,.3);color:#fff;cursor:pointer;display:flex;height:40px;justify-content:center;position:absolute;right:6px;top:50%;transform:translateY(-50%);transition:all .2s ease;width:40px}.ai-chat-trigger-input-btn:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,119,255,.4);transform:translateY(-50%) scale(1.05)}.ai-chat-trigger-input-btn:active:not(:disabled){transform:translateY(-50%) scale(.95)}.ai-chat-trigger-input-btn:disabled{box-shadow:none;cursor:not-allowed;opacity:.4}.ai-chat-trigger-input-btn svg{height:18px;width:18px}.ai-chat-widget.light .ai-chat-trigger-input{backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);background:hsla(0,0%,100%,.7);border:1px solid rgba(0,0,0,.1);box-shadow:0 4px 24px rgba(0,0,0,.08);color:var(--input-text,#1a1a1a)}.ai-chat-widget.light .ai-chat-trigger-input::placeholder{color:var(--text-placeholder,rgba(0,0,0,.4))}.ai-chat-widget.light .ai-chat-trigger-input:focus{background:hsla(0,0%,100%,.85);border-color:rgba(0,0,0,.2)}.ai-chat-widget.light .ai-chat-trigger-input-btn{background:var(--primary-color,var(--button-color,#07f));box-shadow:0 2px 8px rgba(0,119,255,.25);color:#fff}.ai-chat-widget.light .ai-chat-trigger-input-btn:hover:not(:disabled){box-shadow:0 4px 12px rgba(0,119,255,.35)}.ai-chat-widget-container.trigger-input-bar{align-items:flex-end;display:flex;flex-direction:column;gap:12px}.ai-chat-widget-container.trigger-input-bar.bottom-left,.ai-chat-widget-container.trigger-input-bar.top-left{align-items:flex-start}.ai-chat-widget-container.trigger-input-bar .ai-chat-window{bottom:auto;left:auto;order:-1;position:relative;right:auto;top:auto;width:100%}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-small{max-width:calc(100vw - 40px);width:380px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-medium{max-width:calc(100vw - 40px);width:420px}.ai-chat-widget-container.trigger-input-bar .ai-chat-window.size-large{max-width:calc(100vw - 40px);width:480px}.ai-chat-widget-container.trigger-input-bar .ai-chat-button,.ai-chat-widget-container.trigger-pill-text .ai-chat-button{display:none}.ai-chat-widget-container.trigger-pill-text.is-open{gap:8px}.ai-chat-input-container{background:var(--bg-primary,#fff);bottom:0;left:0;padding:8px 0 16px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:var(--bg-primary,#282625)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px)}.ai-chat-input-wrapper{align-items:flex-end;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);box-sizing:border-box;display:flex;gap:0;height:52px;overflow:hidden;padding:6px 6px 6px 16px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-input-wrapper.multiline{border-radius:14px!important;min-height:64px;padding:10px 10px 10px 14px}.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{word-wrap:break-word!important;background:transparent!important;border:none!important;border-radius:0!important;box-shadow:none!important;box-sizing:border-box!important;color:var(--input-text,#000)!important;flex:1!important;font-family:inherit!important;font-size:var(--text-md,15px)!important;height:40px!important;line-height:20px!important;margin:0!important;max-height:40px!important;min-height:40px!important;min-width:0!important;outline:none!important;overflow-wrap:anywhere!important;overflow-x:hidden!important;overflow-y:auto!important;padding:10px var(--space-sm,8px)!important;resize:none!important;white-space:pre-wrap!important;width:0!important;word-break:break-word!important}.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;align-self: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;align-self: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;min-height:40px;min-width:40px;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-data-policy{bottom:2px;color:var(--text-muted,#71717a);font-size:9px;left:0;line-height:1.4;opacity:.5;pointer-events:auto;position:absolute;right:0;text-align:center}.ai-chat-widget.dark .ai-chat-data-policy{color:var(--text-muted,#a1a1aa)}.ai-chat-data-policy-link{background:none;border:none;color:var(--text-muted,#71717a);cursor:pointer;font-family:inherit;font-size:inherit;margin:0;padding:0;text-decoration:underline;text-underline-offset:2px;transition:color .15s ease}.ai-chat-data-policy-link:hover{color:var(--text-secondary,#52525b)}.ai-chat-widget.dark .ai-chat-data-policy-link{color:var(--text-muted,#a1a1aa)}.ai-chat-widget.dark .ai-chat-data-policy-link:hover{color:var(--text-secondary,#d4d4d8)}.ai-chat-page-disclaimer{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:10px;gap:4px;justify-content:center;line-height:1.4;opacity:.7;padding:8px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-page-disclaimer{color:var(--text-muted,#a1a1aa)}.ai-chat-page-disclaimer-link{background:none;border:none;color:var(--text-muted,#71717a);cursor:pointer;font-family:inherit;font-size:inherit;margin:0;padding:0;text-decoration:underline;text-underline-offset:2px;transition:color .15s ease}.ai-chat-page-disclaimer-link:hover{color:var(--text-secondary,#52525b)}.ai-chat-widget.dark .ai-chat-page-disclaimer-link{color:var(--text-muted,#a1a1aa)}.ai-chat-widget.dark .ai-chat-page-disclaimer-link:hover{color:var(--text-secondary,#d4d4d8)}.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:0 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:ai-chat-message-slide-in .2s var(--spring-bounce);display:flex;flex-direction:column;max-width:90%}.ai-chat-message.user{align-items:flex-end;align-self:flex-end}.ai-chat-message.assistant{align-items:flex-start;align-self:flex-start;max-width:100%;width:100%}.ai-chat-message.tool{align-self:stretch;max-width:none;padding:0}.ai-chat-message-content{word-wrap:break-word;border-radius:18px;font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);overflow-wrap:break-word;padding:8px 14px}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border-radius:18px;color:var(--user-text,#000)}.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.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);box-sizing:border-box;color:var(--agent-text,#000);padding:0;width:100%}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fff)}.ai-chat-message-timestamp{color:var(--text-muted,#71717a);font-size:var(--text-xs,12px);margin-top:var(--space-xs,4px);padding:0 var(--space-xs,4px)}.ai-chat-welcome{animation:ai-chat-welcome-fade-in .3s var(--spring-smooth);display:flex;flex-direction:column;gap:var(--space-md,16px);padding:var(--space-lg,24px) 0}.ai-chat-welcome-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-2xl,28px);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3)}.ai-chat-widget.dark .ai-chat-welcome-title{color:var(--text-primary,#fff)}.ai-chat-welcome-text{color:var(--text-secondary,#000);font-size:var(--text-md,15px);line-height:var(--line-height-relaxed,1.6);max-width:100%}.ai-chat-widget.dark .ai-chat-welcome-text{color:var(--text-secondary,#fff)}.ai-chat-typing{align-items:center;display:flex;gap:var(--space-xs,4px);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-typing-dot{animation:ai-chat-typing-bounce 1.4s ease-in-out infinite both;background:var(--text-muted,#71717a);border-radius:50%;height:8px;width:8px}.ai-chat-typing-dot:first-child{animation-delay:-.32s}.ai-chat-typing-dot:nth-child(2){animation-delay:-.16s}.ai-chat-typing-dot:nth-child(3){animation-delay:0s}@keyframes ai-chat-typing-bounce{0%,80%,to{opacity:.4;transform:scale(.6)}40%{opacity:1;transform:scale(1)}}.ai-chat-scroll-button{align-items:center;background:var(--bg-secondary,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:50%;bottom:80px;box-shadow:0 2px 8px rgba(0,0,0,.1);color:var(--text-secondary,#71717a);cursor:pointer;display:flex;height:36px;justify-content:center;left:50%;opacity:0;pointer-events:none;position:absolute;transform:translateX(-50%);transition:background .15s ease,box-shadow .15s ease,opacity .15s ease,visibility .15s ease;visibility:hidden;width:36px;z-index:15}.ai-chat-scroll-button.visible{opacity:1;pointer-events:auto;visibility:visible}.ai-chat-scroll-button:hover{background:var(--bg-tertiary,#e4e4e7);box-shadow:0 4px 12px rgba(0,0,0,.15)}.ai-chat-scroll-button:active{background:var(--bg-tertiary,#d4d4d8)}.ai-chat-widget.dark .ai-chat-scroll-button{background:var(--bg-secondary,#3f3f46);border-color:var(--border-subtle,hsla(0,0%,100%,.1));box-shadow:0 2px 8px rgba(0,0,0,.3);color:var(--text-secondary,#a1a1aa)}.ai-chat-widget.dark .ai-chat-scroll-button:hover{background:var(--bg-tertiary,#52525b);box-shadow:0 4px 12px rgba(0,0,0,.4)}.ai-chat-error{background:var(--bg-secondary);border-radius:var(--radius-chat-bubble);color:var(--text-primary);font-size:var(--text-md);margin:0 auto;padding:10px var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 var(--space-sm) 0}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content h1{font-size:1.5em}.ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-message.assistant .ai-chat-message-content h2{color:var(--text-primary,#3e3e3e);font-weight:var(--font-weight-bold,700);line-height:var(--line-height-tight,1.3);margin:var(--space-md,16px) 0 var(--space-sm,8px) 0}.ai-chat-message.assistant .ai-chat-message-content h2{font-size:1.3em}.ai-chat-message.assistant .ai-chat-message-content h3{color:var(--text-primary,#3e3e3e);font-size:1.15em;font-weight:var(--font-weight-semibold,600);line-height:var(--line-height-tight,1.3);margin:var(--space-sm,8px) 0 var(--space-xs,4px) 0}.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{color:var(--text-primary,#3e3e3e);font-size:1em;font-weight:var(--font-weight-semibold,600);line-height:var(--line-height-tight,1.3);margin:var(--space-sm,8px) 0 var(--space-xs,4px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h2,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h3,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content h6{color:var(--text-primary,#fff)}.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,.ai-chat-message.assistant .ai-chat-message-content>h4:first-child,.ai-chat-message.assistant .ai-chat-message-content>h5:first-child,.ai-chat-message.assistant .ai-chat-message-content>h6:first-child{margin-top:0}.ai-chat-message.assistant .ai-chat-message-content ul{list-style-type:disc;margin:var(--space-sm,8px) 0;padding-left:var(--space-lg,24px)}.ai-chat-message.assistant .ai-chat-message-content ul ul{list-style-type:circle;margin:var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content ul ul ul{list-style-type:square}.ai-chat-message.assistant .ai-chat-message-content ol{list-style-type:decimal;margin:var(--space-sm,8px) 0;padding-left:var(--space-lg,24px)}.ai-chat-message.assistant .ai-chat-message-content ol ol{list-style-type:lower-alpha;margin:var(--space-xs,4px) 0}.ai-chat-message.assistant .ai-chat-message-content ol ol ol{list-style-type:lower-roman}.ai-chat-message.assistant .ai-chat-message-content li{margin-bottom:var(--space-xs,4px);padding-left:var(--space-xs,4px)}.ai-chat-message.assistant .ai-chat-message-content li:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content li>ol,.ai-chat-message.assistant .ai-chat-message-content li>ul{margin-top:var(--space-xs,4px)}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.05);border-radius:var(--radius-sm);font-family:SF Mono,Monaco,Cascadia Code,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,.05);border-radius:var(--radius-md);margin:var(--space-sm) 0;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%,.05)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;padding:0}.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 strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--border-default);color:var(--text-muted);margin:var(--space-sm) 0;padding-left:var(--space-md)}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle,rgba(0,0,0,.1));margin:var(--space-lg,24px) 0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content hr{border-top-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content .table-wrapper{border:1px solid var(--border-subtle,rgba(0,0,0,.1));border-radius:var(--radius-md,8px);box-sizing:border-box;display:block;margin:var(--space-sm) var(--space-sm);max-width:100%;overflow:hidden;width:auto}.ai-chat-message.assistant .ai-chat-message-content .table-scroll{max-width:100%;overflow-x:auto;overflow-y:hidden;width:100%}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content .table-wrapper{border-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content table{border-collapse:collapse;font-size:var(--text-sm);min-width:100%;width:max-content}.ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-message.assistant .ai-chat-message-content th{border-bottom:1px solid var(--border-subtle,rgba(0,0,0,.1));border-right:1px solid var(--border-subtle,rgba(0,0,0,.1));padding:var(--space-sm);text-align:left}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content td,.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content th{border-color:var(--border-subtle,hsla(0,0%,100%,.1))}.ai-chat-message.assistant .ai-chat-message-content td:last-child,.ai-chat-message.assistant .ai-chat-message-content th:last-child{border-right:none}.ai-chat-message.assistant .ai-chat-message-content tr:last-child td{border-bottom:none}.ai-chat-message.assistant .ai-chat-message-content th{background:rgba(0,0,0,.03);font-weight:var(--font-weight-semibold);white-space:nowrap}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content th{background:hsla(0,0%,100%,.05)}.ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:rgba(0,0,0,.02)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content tbody tr:nth-child(2n){background:hsla(0,0%,100%,.03)}.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{align-items:center;background:transparent;border:1px solid var(--border-default,#d4d4d8);border-radius:var(--radius-preset-badge,18px);color:var(--text-primary,#18181b);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,border-color .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:transparent;border-color:var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{background:var(--bg-hover,#f4f4f5);border-color:var(--border-default,#d4d4d8)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{background:var(--bg-hover,#3f3f46);border-color:var(--border-subtle,#52525b)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question.action-type{border:none}.ai-chat-suggested-question.action-type,.ai-chat-widget.dark .ai-chat-suggested-question.action-type{background:var(--primary-color,var(--button-color,#ef4444));color:var(--button-icon-color,#fff)}.ai-chat-suggested-question.action-type:hover{background:var(--primary-color,var(--button-color,#ef4444));opacity:.9}.ai-chat-suggested-question-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-suggested-question:not(.action-type) .ai-chat-suggested-question-icon{display:none}.ai-chat-follow-up-suggestions{box-sizing:border-box;margin:0;padding:8px 16px 0;width:100%}.ai-chat-follow-up-list{align-items:flex-end;display:flex;flex-direction:column;gap:6px}.ai-chat-follow-up-item{align-items:center;border:none;border-radius:var(--radius-preset-badge,18px);cursor:pointer;display:inline-flex;font-size:14px;font-weight:400;gap:6px;justify-content:center;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:opacity .15s ease,transform .1s ease;white-space:nowrap}.ai-chat-follow-up-item,.ai-chat-widget.dark .ai-chat-follow-up-item{background:var(--primary-color,var(--button-color,#07f));color:var(--button-icon-color,#fff)}.ai-chat-follow-up-item:hover{opacity:.9}.ai-chat-follow-up-item:active{transform:scale(.98)}.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type,.dark .ai-chat-follow-up-item.question-type,[data-color-mode=dark] .ai-chat-follow-up-item.question-type,[data-theme=dark] .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:var(--text-primary,#fafafa)}}.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5);opacity:1}.ai-chat-widget.dark .ai-chat-follow-up-item.question-type:hover,.dark .ai-chat-follow-up-item.question-type:hover,[data-color-mode=dark] .ai-chat-follow-up-item.question-type:hover,[data-theme=dark] .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}@media (prefers-color-scheme:dark){.ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46);opacity:1}}.ai-chat-follow-up-item.action-type{background:var(--primary-color,var(--button-color,#07f));border:none;color:var(--button-icon-color,#fff)}.ai-chat-follow-up-icon{align-items:center;display:flex;flex-shrink:0;justify-content:center}.ai-chat-follow-up-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.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:ai-chat-feedback-morph .3s var(--spring-bounce);gap:var(--space-xs)}.ai-chat-feedback-message{align-items:center;display:flex;gap:4px;margin-left:var(--space-xxs)}.ai-chat-feedback-checkmark{animation:ai-chat-checkmark-pop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-xs);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-xs) 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:center;background:var(--user-bg,#f4f4f5);border-radius:var(--radius-history-item,15px);display:flex;flex:0 0 auto;flex-direction:row;height:var(--history-item-height,36px);margin:0;overflow:hidden;transition:background var(--duration-fast,.15s) ease;width:100%}.ai-chat-history-item-content{align-items:center;background:transparent;border:none;cursor:pointer;display:flex;flex:1;flex-direction:row;height:100%;min-width:0;padding:0 var(--space-xs,4px) 0 var(--space-md,16px);text-align:left}.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);flex:1;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-history-item-delete{align-items:center;background:transparent;border:none;border-radius:var(--radius-sm,6px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:24px;justify-content:center;margin-left:auto;margin-right:var(--space-xs,4px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:24px}.ai-chat-history-item-delete svg{height:14px;width:14px}.ai-chat-history-item:hover .ai-chat-history-item-delete{opacity:1}.ai-chat-history-item-delete:hover{background:rgba(239,68,68,.1);color:#ef4444}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{background:rgba(239,68,68,.2);color:#f87171}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0;padding:0}.ai-chat-tool-gear{color:#1f2937;flex-shrink:0;height:20px;width:20px}.ai-chat-tool-gear.spinning{animation:ai-chat-gear-spin 1.5s linear infinite}.ai-chat-tool-badges{align-items:center;display:flex;flex-wrap:wrap;gap:8px}.ai-chat-tool-badge{align-items:center;background:#e5e7eb;border:1px solid #d1d5db;border-radius:var(--radius-action-badge,8px);color:#1f2937;display:inline-flex;font-size:12px;font-weight:500;gap:4px;line-height:1.2;padding:5px 12px;transition:all .2s ease;white-space:nowrap}.ai-chat-tool-badge.loading{animation:ai-chat-tool-gradient 2s linear infinite;background:linear-gradient(90deg,var(--tool-loading-bg-1,#e0e0e0) 0,var(--tool-loading-bg-2,#f0f0f0) 25%,var(--tool-loading-bg-3,#fff) 50%,var(--tool-loading-bg-2,#f0f0f0) 75%,var(--tool-loading-bg-1,#e0e0e0) 100%);background-size:200% 100%;color:var(--tool-loading-text,#1a1a1a);position:relative}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.loading{--tool-loading-bg-1:#2a2a2a;--tool-loading-bg-2:#3a3a3a;--tool-loading-bg-3:#4a4a4a;--tool-loading-text:#fff}.ai-chat-tool-badge.completed{background:#e5e7eb;border:1px solid #d1d5db;color:#1f2937}.ai-chat-widget.dark .ai-chat-tool-badge,.ai-chat-widget[data-theme=dark] .ai-chat-tool-badge,.chakra-ui-dark .ai-chat-tool-badge,.dark .ai-chat-tool-badge,[data-theme=dark] .ai-chat-tool-badge,html.dark .ai-chat-tool-badge{background:hsla(0,0%,100%,.12);border:1px solid hsla(0,0%,100%,.2);color:hsla(0,0%,100%,.9)}.ai-chat-widget.dark .ai-chat-tool-gear,.ai-chat-widget[data-theme=dark] .ai-chat-tool-gear,.chakra-ui-dark .ai-chat-tool-gear,.dark .ai-chat-tool-gear,[data-theme=dark] .ai-chat-tool-gear,html.dark .ai-chat-tool-gear{color:#fff}.ai-chat-tool-badge.error{background:var(--tool-error-bg,rgba(239,68,68,.15));color:var(--tool-error-text,#ef4444)}.ai-chat-tool-badge .ai-chat-tool-check{color:#fff;flex-shrink:0}.ai-chat-tool-badge .ai-chat-tool-error{color:#ef4444;flex-shrink:0}.tool-name{font-weight:500;line-height:1.2;white-space:nowrap}.ai-chat-tool-action{box-sizing:border-box;padding:0;width:100%}@keyframes ai-chat-skeleton-pulse{0%,to{opacity:.4}50%{opacity:.7}}.ai-chat-action-skeleton-item{animation:ai-chat-skeleton-pulse 1.5s ease-in-out infinite;background:var(--bg-secondary,#e5e7eb)}.ai-chat-widget.dark .ai-chat-action-skeleton-item,.chakra-ui-dark .ai-chat-action-skeleton-item,.dark .ai-chat-action-skeleton-item,[data-theme=dark] .ai-chat-action-skeleton-item{background:hsla(0,0%,100%,.1)}.ai-chat-action-skeleton-content{display:flex;flex-direction:column;gap:16px}.ai-chat-action-skeleton-header{align-items:center;display:flex;gap:10px}.ai-chat-action-skeleton-box{background:rgba(0,0,0,.08);border-radius:10px;display:flex;flex-direction:column;gap:8px;padding:14px}.ai-chat-widget.dark .ai-chat-action-skeleton-box,.chakra-ui-dark .ai-chat-action-skeleton-box,.dark .ai-chat-action-skeleton-box,[data-theme=dark] .ai-chat-action-skeleton-box{background:rgba(0,0,0,.25)}.ai-chat-action-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin-top:4px;padding:16px;transition:all .2s ease;width:100%}.ai-chat-widget.dark .ai-chat-action-card,.chakra-ui-dark .ai-chat-action-card,.dark .ai-chat-action-card,[data-theme=dark] .ai-chat-action-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-action-booked{background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06))}.ai-chat-widget.dark .ai-chat-action-booked,.chakra-ui-dark .ai-chat-action-booked,.dark .ai-chat-action-booked,[data-theme=dark] .ai-chat-action-booked{background:var(--bg-secondary,#3a3a3a)}.ai-chat-action-header{align-items:center;color:var(--text-primary,#3e3e3e);display:flex;font-size:var(--text-md,15px);font-weight:var(--font-weight-semibold,600);gap:var(--space-sm,8px);margin-bottom:var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-action-header,.chakra-ui-dark .ai-chat-action-header,.dark .ai-chat-action-header,[data-theme=dark] .ai-chat-action-header{color:var(--text-primary,#fff)}.ai-chat-action-icon{color:var(--action-accent,var(--primary-color,#3b82f6));flex-shrink:0;height:20px;width:20px}.ai-chat-action-success-icon-wrapper{align-items:center;background:var(--action-accent,var(--primary-color,#22c55e));border-radius:50%;color:#fff;display:flex;flex-shrink:0;height:24px;justify-content:center;width:24px}.ai-chat-action-icon-success{color:currentColor;height:14px;width:14px}.ai-chat-action-detail-box{background:var(--bg-primary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-md,8px);display:flex;flex-direction:column;gap:4px;padding:12px 16px}.ai-chat-widget.dark .ai-chat-action-detail-box,.chakra-ui-dark .ai-chat-action-detail-box,.dark .ai-chat-action-detail-box,[data-theme=dark] .ai-chat-action-detail-box{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.05)}.ai-chat-action-label-small{color:var(--text-muted,#71717a);font-size:11px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-action-value-large{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:500}.ai-chat-widget.dark .ai-chat-action-value-large,.chakra-ui-dark .ai-chat-action-value-large,.dark .ai-chat-action-value-large,[data-theme=dark] .ai-chat-action-value-large{color:#fff}.ai-chat-action-body{display:flex;flex-direction:column;gap:var(--space-md,16px)}.ai-chat-action-close-btn{align-items:center;background:transparent;border:none;border-radius:6px;color:var(--ai-chat-fg-muted,#6b7280);cursor:pointer;display:flex;height:28px;justify-content:center;padding:0;position:absolute;right:12px;top:12px;transition:all .15s ease;width:28px;z-index:10}.ai-chat-action-close-btn:hover{background:var(--ai-chat-bg-muted,#f3f4f6);color:var(--ai-chat-fg,#1f2937)}.ai-chat-action-close-btn:active{transform:scale(.95)}.ai-chat-action-close-btn:focus-visible{outline:2px solid var(--ai-chat-accent,#2563eb);outline-offset:2px}.ai-chat-action-card--closable,.ai-chat-form-card--closable{position:relative}.ai-chat-action-card--closable .ai-chat-action-header,.ai-chat-form-card--closable .ai-chat-form-card__header{padding-right:40px}.ai-chat-widget.dark .ai-chat-action-close-btn:hover,.chakra-ui-dark .ai-chat-action-close-btn:hover,.dark .ai-chat-action-close-btn:hover,[data-theme=dark] .ai-chat-action-close-btn:hover{background:hsla(0,0%,100%,.1);color:var(--ai-chat-fg,#f3f4f6)}.ai-chat-action-field{display:flex;flex-direction:column;gap:var(--space-xs,6px)}.ai-chat-action-label{color:var(--text-secondary,#6b7280);font-size:var(--text-sm,13px);font-weight:var(--font-weight-medium,500)}.ai-chat-widget.dark .ai-chat-action-label,.chakra-ui-dark .ai-chat-action-label,.dark .ai-chat-action-label,[data-theme=dark] .ai-chat-action-label{color:var(--text-secondary,#a1a1aa)}.ai-chat-action-input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);font-size:var(--text-sm,13px);outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease}.ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-action-input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-action-input,.chakra-ui-dark .ai-chat-action-input,.dark .ai-chat-action-input,[data-theme=dark] .ai-chat-action-input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-input:focus,.chakra-ui-dark .ai-chat-action-input:focus,.dark .ai-chat-action-input:focus,[data-theme=dark] .ai-chat-action-input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-action-button{background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;color:#fff;cursor:pointer;font-size:var(--text-sm,13px);font-weight:var(--font-weight-semibold,600);padding:12px 16px;transition:all .2s ease;width:100%}.ai-chat-action-button:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.5}.ai-chat-action-link-button{align-items:center;background:var(--action-accent,var(--primary-color,#3b82f6));border:none;border-radius:9999px;box-sizing:border-box;color:#fff;display:flex;font-size:14px;font-weight:600;gap:6px;justify-content:center;margin-top:8px;padding:12px;text-decoration:none;transition:all .2s ease;width:100%}.ai-chat-action-link-button:hover{opacity:.9;transform:translateY(-1px)}.ai-chat-action-error{background:rgba(239,68,68,.1);border-radius:var(--radius-md,8px);color:#dc2626;font-size:var(--text-sm,13px);padding:10px 12px}.ai-chat-widget.dark .ai-chat-action-error,.chakra-ui-dark .ai-chat-action-error,.dark .ai-chat-action-error,[data-theme=dark] .ai-chat-action-error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-action-hint{color:var(--text-muted,#9ca3af);font-size:var(--text-sm,13px);padding:var(--space-sm,8px);text-align:center}.ai-chat-action-date-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(90px,1fr))}.ai-chat-action-date-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-date-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn,.chakra-ui-dark .ai-chat-action-date-btn,.dark .ai-chat-action-date-btn,[data-theme=dark] .ai-chat-action-date-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-date-btn:hover,.chakra-ui-dark .ai-chat-action-date-btn:hover,.dark .ai-chat-action-date-btn:hover,[data-theme=dark] .ai-chat-action-date-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-date-btn.active,.chakra-ui-dark .ai-chat-action-date-btn.active,.dark .ai-chat-action-date-btn.active,[data-theme=dark] .ai-chat-action-date-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-action-time-grid{display:grid;gap:var(--space-xs,6px);grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}.ai-chat-action-time-btn{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;font-size:var(--text-xs,12px);font-weight:var(--font-weight-medium,500);padding:8px 10px;text-align:center;transition:all .15s ease}.ai-chat-action-time-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn,.chakra-ui-dark .ai-chat-action-time-btn,.dark .ai-chat-action-time-btn,[data-theme=dark] .ai-chat-action-time-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-action-time-btn:hover,.chakra-ui-dark .ai-chat-action-time-btn:hover,.dark .ai-chat-action-time-btn:hover,[data-theme=dark] .ai-chat-action-time-btn:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-action-time-btn.active,.chakra-ui-dark .ai-chat-action-time-btn.active,.dark .ai-chat-action-time-btn.active,[data-theme=dark] .ai-chat-action-time-btn.active{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-link-preview{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:var(--radius-lg,12px);cursor:pointer;display:flex;flex-direction:column;margin-top:4px;overflow:hidden;padding:0!important;position:relative;transition:border-color .2s,box-shadow .2s,transform .2s}.ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 8px rgba(0,0,0,.1);transform:translateY(-1px)}.ai-chat-link-preview:focus{border-color:var(--action-accent);box-shadow:0 0 0 2px rgba(59,130,246,.2);outline:none}.ai-chat-widget.dark .ai-chat-link-preview,.chakra-ui-dark .ai-chat-link-preview,.dark .ai-chat-link-preview,[data-theme=dark] .ai-chat-link-preview{background:var(--bg-secondary,#3a3a3a);border-color:hsla(0,0%,100%,.08)}.ai-chat-widget.dark .ai-chat-link-preview:hover,.chakra-ui-dark .ai-chat-link-preview:hover,.dark .ai-chat-link-preview:hover,[data-theme=dark] .ai-chat-link-preview:hover{border-color:var(--action-accent);box-shadow:0 2px 12px rgba(0,0,0,.3)}.ai-chat-link-preview__image{aspect-ratio:1.91/1;background:var(--bg-muted,#e5e7eb);overflow:hidden;width:100%}.ai-chat-widget.dark .ai-chat-link-preview__image,.chakra-ui-dark .ai-chat-link-preview__image,.dark .ai-chat-link-preview__image,[data-theme=dark] .ai-chat-link-preview__image{background:hsla(0,0%,100%,.05)}.ai-chat-link-preview__image img{height:100%;object-fit:cover;width:100%}.ai-chat-link-preview__content{flex:1;padding:8px 10px}.ai-chat-link-preview__site{align-items:center;display:flex;gap:6px;margin-bottom:6px}.ai-chat-link-preview__favicon{border-radius:2px;flex-shrink:0;height:16px;width:16px}.ai-chat-link-preview__domain{color:var(--text-muted,#71717a);font-size:12px;letter-spacing:.5px;overflow:hidden;text-overflow:ellipsis;text-transform:uppercase;white-space:nowrap}.ai-chat-link-preview__title{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-primary,#3e3e3e);display:-webkit-box;font-size:15px;font-weight:600;line-height:1.3;margin:0 0 4px;overflow:hidden}.ai-chat-widget.dark .ai-chat-link-preview__title,.chakra-ui-dark .ai-chat-link-preview__title,.dark .ai-chat-link-preview__title,[data-theme=dark] .ai-chat-link-preview__title{color:#fff}.ai-chat-link-preview__description{-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;color:var(--text-muted,#71717a);display:-webkit-box;font-size:13px;line-height:1.4;margin:0;overflow:hidden}.ai-chat-link-preview__context{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:8px 0 0;padding-top:8px}.ai-chat-widget.dark .ai-chat-link-preview__context,.chakra-ui-dark .ai-chat-link-preview__context,.dark .ai-chat-link-preview__context,[data-theme=dark] .ai-chat-link-preview__context{border-color:hsla(0,0%,100%,.08)}.ai-chat-link-preview__arrow{align-items:center;background:var(--bg-primary,#fff);border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.1);color:var(--text-muted,#71717a);display:flex;height:28px;justify-content:center;opacity:0;position:absolute;right:12px;top:12px;transition:opacity .2s,background .2s;width:28px}.ai-chat-link-preview:hover .ai-chat-link-preview__arrow{opacity:1}.ai-chat-widget.dark .ai-chat-link-preview__arrow,.chakra-ui-dark .ai-chat-link-preview__arrow,.dark .ai-chat-link-preview__arrow,[data-theme=dark] .ai-chat-link-preview__arrow{background:hsla(0,0%,100%,.1);color:#fff}.ai-chat-link-preview--error{border-color:rgba(239,68,68,.3)}.ai-chat-link-preview--error:hover{border-color:rgba(239,68,68,.5)}.ai-chat-link-preview__error-text{color:#dc2626;font-size:12px;margin:4px 0 0}.ai-chat-widget.dark .ai-chat-link-preview__error-text,.chakra-ui-dark .ai-chat-link-preview__error-text,.dark .ai-chat-link-preview__error-text,[data-theme=dark] .ai-chat-link-preview__error-text{color:#fca5a5}.ai-chat-video-player{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f4f4f4);border-radius:var(--radius-lg,12px);display:flex;flex-direction:column;gap:0;margin-top:4px;overflow:hidden;padding:0!important}.ai-chat-widget.dark .ai-chat-video-player,.chakra-ui-dark .ai-chat-video-player,.dark .ai-chat-video-player,[data-theme=dark] .ai-chat-video-player{background:var(--bg-secondary,#3a3a3a)}.ai-chat-video-player__header{align-items:center;color:var(--action-accent,var(--primary-color,#3b82f6));display:flex;gap:8px}.ai-chat-video-player__title{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:600}.ai-chat-widget.dark .ai-chat-video-player__title,.chakra-ui-dark .ai-chat-video-player__title,.dark .ai-chat-video-player__title,[data-theme=dark] .ai-chat-video-player__title{color:#fff}.ai-chat-video-player__container{aspect-ratio:16/9;background:#000;border-radius:8px;overflow:hidden;position:relative;width:100%}.ai-chat-video-player__thumbnail{cursor:pointer;height:100%;position:relative;width:100%}.ai-chat-video-player__thumbnail img{height:100%;object-fit:cover;width:100%}.ai-chat-video-player__placeholder{align-items:center;background:linear-gradient(135deg,#1a1a2e,#16213e);cursor:pointer;display:flex;flex-direction:column;gap:8px;height:100%;justify-content:center;position:relative;width:100%}.ai-chat-video-player__click-text{color:hsla(0,0%,100%,.7);font-size:13px}.ai-chat-video-player__play-btn{align-items:center;background:rgba(0,0,0,.7);border:none;border-radius:50%;color:#fff;cursor:pointer;display:flex;height:64px;justify-content:center;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);transition:background .2s,transform .2s;width:64px}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn{left:auto;position:relative;top:auto;transform:none}.ai-chat-video-player__play-btn:hover{background:rgba(0,0,0,.9);transform:translate(-50%,-50%) scale(1.05)}.ai-chat-video-player__placeholder .ai-chat-video-player__play-btn:hover{transform:scale(1.05)}.ai-chat-video-player__provider-badge{background:rgba(0,0,0,.8);border-radius:4px;bottom:8px;color:#fff;font-size:11px;font-weight:600;letter-spacing:.5px;padding:4px 8px;position:absolute;right:8px;text-transform:uppercase}.ai-chat-video-player__iframe,.ai-chat-video-player__video{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.ai-chat-video-player__error{align-items:center;background:rgba(239,68,68,.1);color:#dc2626;display:flex;font-size:13px;height:100%;justify-content:center;padding:16px;text-align:center;width:100%}.ai-chat-widget.dark .ai-chat-video-player__error,.chakra-ui-dark .ai-chat-video-player__error,.dark .ai-chat-video-player__error,[data-theme=dark] .ai-chat-video-player__error{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-video-player__context{color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin-top:4px;padding:8px 12px 12px}.ai-chat-location-card{background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:12px;overflow:hidden;padding:0}.ai-chat-widget.dark .ai-chat-location-card,.chakra-ui-dark .ai-chat-location-card,.dark .ai-chat-location-card,[data-theme=dark] .ai-chat-location-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-location-card--compact{border-radius:10px}.ai-chat-location-card--error{color:var(--text-muted,#71717a);padding:16px;text-align:center}.ai-chat-location-card__map{background:var(--bg-muted,#f4f4f5);position:relative;width:100%}.ai-chat-widget.dark .ai-chat-location-card__map,.chakra-ui-dark .ai-chat-location-card__map,.dark .ai-chat-location-card__map,[data-theme=dark] .ai-chat-location-card__map{background:rgba(0,0,0,.2)}.ai-chat-location-card__map iframe{border:none;display:block;height:100%;width:100%}.ai-chat-location-card__content{padding:12px}.ai-chat-location-card--compact .ai-chat-location-card__content{padding:10px}.ai-chat-location-card__header{align-items:center;display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}.ai-chat-location-card__name{color:var(--text-primary,#18181b);flex:1;font-size:16px;font-weight:600;margin:0;min-width:0}.ai-chat-widget.dark .ai-chat-location-card__name,.chakra-ui-dark .ai-chat-location-card__name,.dark .ai-chat-location-card__name,[data-theme=dark] .ai-chat-location-card__name{color:#fff}.ai-chat-location-card--compact .ai-chat-location-card__name{font-size:14px}.ai-chat-location-card__type{background:var(--bg-muted,#f4f4f5);border-radius:10px;color:var(--text-muted,#71717a);font-size:11px;font-weight:500;letter-spacing:.5px;padding:2px 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-location-card__type,.chakra-ui-dark .ai-chat-location-card__type,.dark .ai-chat-location-card__type,[data-theme=dark] .ai-chat-location-card__type{background:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.7)}.ai-chat-location-card__status{border-radius:12px;font-size:12px;font-weight:500;padding:2px 8px}.ai-chat-location-card__status--open{background:#dcfce7;color:#16a34a}.ai-chat-location-card__status--closed{background:#fef2f2;color:#dc2626}.ai-chat-widget.dark .ai-chat-location-card__status--open,.chakra-ui-dark .ai-chat-location-card__status--open,.dark .ai-chat-location-card__status--open,[data-theme=dark] .ai-chat-location-card__status--open{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-widget.dark .ai-chat-location-card__status--closed,.chakra-ui-dark .ai-chat-location-card__status--closed,.dark .ai-chat-location-card__status--closed,[data-theme=dark] .ai-chat-location-card__status--closed{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-location-card__address{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__address svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 8px}.ai-chat-location-card__hours{align-items:flex-start;color:var(--text-muted,#71717a);display:flex;font-size:13px;gap:6px;margin-bottom:8px}.ai-chat-location-card__hours svg{flex-shrink:0;margin-top:2px}.ai-chat-location-card__hours-list{flex:1}.ai-chat-location-card__hours-toggle{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;font:inherit;gap:4px;padding:0}.ai-chat-location-card__hours-toggle:hover{text-decoration:underline}.ai-chat-location-card__hours-full{list-style:none;margin:8px 0 0;padding:0}.ai-chat-location-card__hours-full li{display:flex;font-size:12px;justify-content:space-between;padding:4px 0}.ai-chat-location-card__hours-today{color:var(--text-primary,#18181b);font-weight:600}.ai-chat-widget.dark .ai-chat-location-card__hours-today,.chakra-ui-dark .ai-chat-location-card__hours-today,.dark .ai-chat-location-card__hours-today,[data-theme=dark] .ai-chat-location-card__hours-today{color:#fff}.ai-chat-location-card__phone{align-items:center;background:none;border:none;color:var(--action-accent,#3b82f6);cursor:pointer;display:flex;font-size:13px;gap:6px;margin-bottom:12px;padding:0}.ai-chat-location-card__phone:hover{text-decoration:underline}.ai-chat-location-card__actions{display:flex;gap:8px;justify-content:flex-start;width:100%}.ai-chat-location-card__button{align-items:center;background:var(--action-accent,#3b82f6);border:none;border-radius:20px;color:#fff;cursor:pointer;display:flex;flex:1;font-size:13px;font-weight:500;gap:6px;justify-content:center;padding:10px 16px;transition:opacity .2s}.ai-chat-location-card__button:hover{opacity:.9}.ai-chat-location-card--compact .ai-chat-location-card__button{font-size:12px;padding:8px 12px}.ai-chat-location-card__link{align-items:center;background:var(--bg-secondary,#fff);border:1px solid var(--border-subtle,rgba(0,0,0,.08));border-radius:20px;color:var(--text-primary,#18181b);display:flex;font-size:13px;gap:6px;padding:10px 16px;text-decoration:none;transition:border-color .2s}.ai-chat-widget.dark .ai-chat-location-card__link,.chakra-ui-dark .ai-chat-location-card__link,.dark .ai-chat-location-card__link,[data-theme=dark] .ai-chat-location-card__link{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-location-card__link:hover{border-color:var(--action-accent,#3b82f6)}.ai-chat-location-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-location-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:4px;padding:0 4px}.ai-chat-location-card-list__stack{display:grid;gap:12px;grid-template-columns:1fr}.ai-chat-location-card-list__stack--cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.ai-chat-location-card-list__stack--cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:1000px){.ai-chat-location-card-list__stack--cols-3{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:640px){.ai-chat-location-card-list__stack--cols-2,.ai-chat-location-card-list__stack--cols-3{grid-template-columns:1fr}}.ai-chat-location-card-list__grid{display:grid;gap:8px;grid-template-columns:repeat(2,1fr)}@media (max-width:400px){.ai-chat-location-card-list__grid{grid-template-columns:1fr}}.ai-chat-location-card-list__carousel{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;scroll-snap-type:x mandatory;scrollbar-width:none}.ai-chat-location-card-list__carousel::-webkit-scrollbar{display:none}.ai-chat-location-card-list__carousel>.ai-chat-location-card{flex:0 0 280px;scroll-snap-align:start}.ai-chat-contact-card{background:#fff;border:1px solid rgba(0,0,0,.08);border-radius:16px;overflow:hidden;padding:0;position:relative}.ai-chat-widget.dark .ai-chat-contact-card,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card,.chakra-ui-dark .ai-chat-contact-card,.dark .ai-chat-contact-card,[data-theme=dark] .ai-chat-contact-card,html.dark .ai-chat-contact-card{background:#4a4a4a;border-color:hsla(0,0%,100%,.08)}.ai-chat-contact-card-list{gap:12px;width:100%}.ai-chat-contact-card--compact{border-radius:12px}.ai-chat-contact-card--empty{align-items:center;background:var(--bg-secondary,#f4f4f5);display:flex;flex-direction:column;gap:8px;justify-content:center;padding:24px 16px;text-align:center}.ai-chat-widget.dark .ai-chat-contact-card--empty,.chakra-ui-dark .ai-chat-contact-card--empty,.dark .ai-chat-contact-card--empty,[data-theme=dark] .ai-chat-contact-card--empty{background:#3a3a3a}.ai-chat-contact-card__empty-icon{color:var(--text-muted,#71717a);opacity:.6}.ai-chat-contact-card__empty-text{color:var(--text-muted,#71717a);font-size:14px;margin:0}.ai-chat-contact-card--vertical{display:flex;flex-direction:column}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-section{aspect-ratio:3/2;overflow:hidden;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image{height:100%;object-fit:cover;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-placeholder{align-items:center;background:linear-gradient(135deg,#5a5a5a,#3a3a3a);color:hsla(0,0%,100%,.5);display:flex;height:100%;justify-content:center;width:100%}.ai-chat-contact-card--vertical .ai-chat-contact-card__image-placeholder svg{height:48px;width:48px}.ai-chat-contact-card--vertical .ai-chat-contact-card__info{padding:16px;text-align:center}.ai-chat-contact-card--horizontal{display:flex;flex-direction:row}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-section{height:160px;min-width:140px;overflow:hidden;width:140px}.ai-chat-contact-card--horizontal.ai-chat-contact-card--compact .ai-chat-contact-card__image-section{height:120px;min-width:100px;width:100px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image{height:100%;object-fit:cover;width:100%}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-placeholder{align-items:center;background:linear-gradient(135deg,#5a5a5a,#3a3a3a);color:hsla(0,0%,100%,.5);display:flex;height:100%;justify-content:center;width:100%}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-placeholder svg{height:36px;width:36px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__info{display:flex;flex:1;flex-direction:column;justify-content:center;padding:16px}.ai-chat-contact-card__name{color:var(--action-accent,#ef4444);font-size:18px;font-weight:600;line-height:1.3;margin:0}.ai-chat-contact-card--compact .ai-chat-contact-card__name{font-size:15px}.ai-chat-contact-card__role{color:rgba(0,0,0,.7);font-size:14px;font-weight:400;margin:2px 0 0}.ai-chat-widget.dark .ai-chat-contact-card__role,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__role,.chakra-ui-dark .ai-chat-contact-card__role,.dark .ai-chat-contact-card__role,[data-theme=dark] .ai-chat-contact-card__role,html.dark .ai-chat-contact-card__role{color:hsla(0,0%,100%,.9)}.ai-chat-contact-card--compact .ai-chat-contact-card__role{font-size:13px}.ai-chat-contact-card__details{display:flex;flex-direction:column;gap:2px;margin-top:12px}.ai-chat-contact-card__detail{color:rgba(0,0,0,.6);display:block;font-size:14px;line-height:1.5;margin:0;text-decoration:none}.ai-chat-contact-card__detail:hover{color:#000;text-decoration:underline}.ai-chat-widget.dark .ai-chat-contact-card__detail,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__detail,.chakra-ui-dark .ai-chat-contact-card__detail,.dark .ai-chat-contact-card__detail,[data-theme=dark] .ai-chat-contact-card__detail,html.dark .ai-chat-contact-card__detail{color:hsla(0,0%,100%,.7)}.ai-chat-widget.dark .ai-chat-contact-card__detail:hover,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__detail:hover,.chakra-ui-dark .ai-chat-contact-card__detail:hover,.dark .ai-chat-contact-card__detail:hover,[data-theme=dark] .ai-chat-contact-card__detail:hover,html.dark .ai-chat-contact-card__detail:hover{color:#fff}.ai-chat-contact-card--compact .ai-chat-contact-card__detail{font-size:13px}.ai-chat-contact-card__responsibilities{display:flex;flex-wrap:wrap;gap:4px;margin-top:8px}.ai-chat-contact-card__responsibility-tag{background:rgba(0,0,0,.08);border-radius:10px;color:rgba(0,0,0,.8);font-size:11px;font-weight:500;padding:3px 10px}.ai-chat-widget.dark .ai-chat-contact-card__responsibility-tag,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__responsibility-tag,.chakra-ui-dark .ai-chat-contact-card__responsibility-tag,.dark .ai-chat-contact-card__responsibility-tag,[data-theme=dark] .ai-chat-contact-card__responsibility-tag,html.dark .ai-chat-contact-card__responsibility-tag{background:hsla(0,0%,100%,.15);color:hsla(0,0%,100%,.9)}.ai-chat-contact-card__responsibility-more{color:rgba(0,0,0,.5);font-size:11px;padding:3px 4px}.ai-chat-widget.dark .ai-chat-contact-card__responsibility-more,.ai-chat-widget[data-theme=dark] .ai-chat-contact-card__responsibility-more,.chakra-ui-dark .ai-chat-contact-card__responsibility-more,.dark .ai-chat-contact-card__responsibility-more,[data-theme=dark] .ai-chat-contact-card__responsibility-more,html.dark .ai-chat-contact-card__responsibility-more{color:hsla(0,0%,100%,.5)}.ai-chat-contact-card__actions{display:flex;gap:8px;padding:0 12px 12px}.ai-chat-contact-card--compact .ai-chat-contact-card__actions{gap:6px;padding:0 10px 10px}.ai-chat-contact-card__button{align-items:center;border:none;border-radius:9999px;cursor:pointer;display:flex;font-size:14px;font-weight:600;gap:8px;justify-content:center;padding:12px 20px;transition:all .15s ease;white-space:nowrap}.ai-chat-contact-card--compact .ai-chat-contact-card__button{font-size:13px;padding:10px 16px}.ai-chat-contact-card__button:hover{box-shadow:0 4px 12px rgba(0,0,0,.15);transform:translateY(-1px)}.ai-chat-contact-card__button:active{transform:translateY(0)}.ai-chat-contact-card__button--primary{background:var(--action-accent,#3b82f6);color:#fff;flex:1}.ai-chat-contact-card__button--primary:hover{background:color-mix(in srgb,var(--action-accent,#3b82f6) 90%,#000)}.ai-chat-contact-card__button--secondary{background:var(--bg-muted,#f4f4f5);border:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-primary,#18181b);flex:1}.ai-chat-contact-card__button--secondary:hover{background:var(--bg-hover,#e4e4e7)}.ai-chat-widget.dark .ai-chat-contact-card__button--secondary,.chakra-ui-dark .ai-chat-contact-card__button--secondary,.dark .ai-chat-contact-card__button--secondary,[data-theme=dark] .ai-chat-contact-card__button--secondary{background:hsla(0,0%,100%,.1);border-color:hsla(0,0%,100%,.15);color:#fff}.ai-chat-widget.dark .ai-chat-contact-card__button--secondary:hover,.chakra-ui-dark .ai-chat-contact-card__button--secondary:hover,.dark .ai-chat-contact-card__button--secondary:hover,[data-theme=dark] .ai-chat-contact-card__button--secondary:hover{background:hsla(0,0%,100%,.15)}.ai-chat-contact-card-list{display:flex;flex-direction:column;gap:8px}.ai-chat-contact-card-list__header{align-items:center;color:var(--text-muted,#71717a);display:flex;font-size:13px;font-weight:500;gap:6px;margin-bottom:2px;margin-top:8px;padding:0 4px}.ai-chat-contact-card-list__stack{display:grid;gap:12px;grid-template-columns:repeat(3,minmax(0,1fr))}@media (max-width:900px){.ai-chat-contact-card-list__stack{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:600px){.ai-chat-contact-card-list__stack{grid-template-columns:1fr}}.ai-chat-contact-card-list__stack--widget{grid-template-columns:1fr}@container (min-width: 380px){.ai-chat-contact-card-list__stack--widget{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (max-width:520px){.ai-chat-contact-card-list__stack{grid-template-columns:1fr!important}.ai-chat-contact-card--horizontal{flex-direction:column}.ai-chat-contact-card--horizontal .ai-chat-contact-card__image-section{aspect-ratio:3/2;height:auto;min-width:100%;width:100%}}.ai-chat-contact-card__initials{align-items:center;display:flex;font-size:48px;font-weight:600;height:100%;justify-content:center;letter-spacing:.05em;text-transform:uppercase;width:100%}.ai-chat-contact-card--compact .ai-chat-contact-card__initials{font-size:32px}.ai-chat-contact-card--horizontal .ai-chat-contact-card__initials{font-size:28px}.ai-chat-contact-card--horizontal.ai-chat-contact-card--compact .ai-chat-contact-card__initials{font-size:22px}.ai-chat-form-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin:6px 0;overflow:hidden;padding:16px;width:100%}.ai-chat-widget.dark .ai-chat-form-card,.chakra-ui-dark .ai-chat-form-card,.dark .ai-chat-form-card,[data-theme=dark] .ai-chat-form-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-form-card--empty,.ai-chat-form-card--error,.ai-chat-form-card--skipped,.ai-chat-form-card--submitted{padding:12px 16px}.ai-chat-form-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-form-card__icon{font-size:18px}.ai-chat-form-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600}.ai-chat-widget.dark .ai-chat-form-card__title,.chakra-ui-dark .ai-chat-form-card__title,.dark .ai-chat-form-card__title,[data-theme=dark] .ai-chat-form-card__title{color:#fff}.ai-chat-form-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0 0 12px}.ai-chat-form-card__context{color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin:0 0 12px}.ai-chat-form-card__error{color:#dc2626;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-form-card__error,.chakra-ui-dark .ai-chat-form-card__error,.dark .ai-chat-form-card__error,[data-theme=dark] .ai-chat-form-card__error{color:#fca5a5}.ai-chat-form-card__success{color:#16a34a;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-form-card__success,.chakra-ui-dark .ai-chat-form-card__success,.dark .ai-chat-form-card__success,[data-theme=dark] .ai-chat-form-card__success{color:#4ade80}.ai-chat-form-card__empty-text,.ai-chat-form-card__skipped-text{color:var(--text-muted,#71717a);font-size:13px;margin:0}.ai-chat-form-card__progress{align-items:center;display:flex;gap:12px;margin-bottom:16px}.ai-chat-form-card__progress-bar{background:var(--action-accent,var(--primary-color,#3b82f6));border-radius:2px;flex:1;height:4px;transition:width .3s ease}.ai-chat-form-card__progress-text{color:var(--text-muted,#71717a);font-size:12px;white-space:nowrap}.ai-chat-form-card__question{margin-bottom:16px}.ai-chat-form-card__question-text{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500;line-height:1.4;margin:0 0 12px}.ai-chat-widget.dark .ai-chat-form-card__question-text,.chakra-ui-dark .ai-chat-form-card__question-text,.dark .ai-chat-form-card__question-text,[data-theme=dark] .ai-chat-form-card__question-text{color:#fff}.ai-chat-form-card__required{color:#dc2626;margin-left:2px}.ai-chat-form-card__answer{margin-top:8px}.ai-chat-form-card__textarea{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:14px;min-height:80px;outline:none;padding:10px 12px;resize:vertical;transition:border-color .2s ease,box-shadow .2s ease;width:100%}.ai-chat-form-card__textarea:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-form-card__textarea::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-form-card__textarea,.chakra-ui-dark .ai-chat-form-card__textarea,.dark .ai-chat-form-card__textarea,[data-theme=dark] .ai-chat-form-card__textarea{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-form-card__textarea:focus,.chakra-ui-dark .ai-chat-form-card__textarea:focus,.dark .ai-chat-form-card__textarea:focus,[data-theme=dark] .ai-chat-form-card__textarea:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-form-card__options{display:flex;flex-direction:column;gap:8px}.ai-chat-form-card__option{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);cursor:pointer;display:flex;gap:10px;padding:10px 12px;transition:border-color .15s,background .15s}.ai-chat-form-card__option:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__option,.chakra-ui-dark .ai-chat-form-card__option,.dark .ai-chat-form-card__option,[data-theme=dark] .ai-chat-form-card__option{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-form-card__option:hover,.chakra-ui-dark .ai-chat-form-card__option:hover,.dark .ai-chat-form-card__option:hover,[data-theme=dark] .ai-chat-form-card__option:hover{background:rgba(59,130,246,.15);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-form-card__option input{accent-color:var(--action-accent,var(--primary-color,#3b82f6));margin:0}.ai-chat-form-card__option-text{color:var(--text-primary,#3e3e3e);font-size:14px}.ai-chat-widget.dark .ai-chat-form-card__option-text,.chakra-ui-dark .ai-chat-form-card__option-text,.dark .ai-chat-form-card__option-text,[data-theme=dark] .ai-chat-form-card__option-text{color:#fff}.ai-chat-form-card__rating{display:flex;flex-wrap:wrap;gap:8px}.ai-chat-form-card__rating-btn{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:var(--radius-md,8px);color:var(--text-primary,#3e3e3e);cursor:pointer;display:flex;font-size:14px;font-weight:500;height:40px;justify-content:center;transition:all .15s ease;width:40px}.ai-chat-form-card__rating-btn--selected,.ai-chat-form-card__rating-btn:hover{border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-form-card__rating-btn--selected{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-widget.dark .ai-chat-form-card__rating-btn,.chakra-ui-dark .ai-chat-form-card__rating-btn,.dark .ai-chat-form-card__rating-btn,[data-theme=dark] .ai-chat-form-card__rating-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-form-card__rating-btn:hover,.chakra-ui-dark .ai-chat-form-card__rating-btn:hover,.dark .ai-chat-form-card__rating-btn:hover,[data-theme=dark] .ai-chat-form-card__rating-btn:hover{border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__rating-btn--selected,.chakra-ui-dark .ai-chat-form-card__rating-btn--selected,.dark .ai-chat-form-card__rating-btn--selected,[data-theme=dark] .ai-chat-form-card__rating-btn--selected{background:var(--action-accent,var(--primary-color,#3b82f6));border-color:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-form-card__actions{align-items:center;border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));display:flex;gap:8px;margin-top:16px;padding-top:16px}.ai-chat-widget.dark .ai-chat-form-card__actions,.chakra-ui-dark .ai-chat-form-card__actions,.dark .ai-chat-form-card__actions,[data-theme=dark] .ai-chat-form-card__actions{border-color:hsla(0,0%,100%,.08)}.ai-chat-form-card__actions-spacer{flex:1}.ai-chat-form-card__btn{border:none;border-radius:9999px;cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:8px 16px;transition:all .2s ease}.ai-chat-form-card__btn:disabled{cursor:not-allowed;opacity:.5}.ai-chat-form-card__btn--primary{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-form-card__btn--primary:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-form-card__btn--secondary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);color:var(--text-primary,#3e3e3e)}.ai-chat-form-card__btn--secondary:hover:not(:disabled){border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-form-card__btn--secondary,.chakra-ui-dark .ai-chat-form-card__btn--secondary,.dark .ai-chat-form-card__btn--secondary,[data-theme=dark] .ai-chat-form-card__btn--secondary{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-form-card__btn--ghost{background:transparent;color:var(--text-muted,#71717a)}.ai-chat-form-card__btn--ghost:hover:not(:disabled){background:rgba(0,0,0,.05);color:var(--text-primary,#3e3e3e)}.ai-chat-widget.dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),.chakra-ui-dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),.dark .ai-chat-form-card__btn--ghost:hover:not(:disabled),[data-theme=dark] .ai-chat-form-card__btn--ghost:hover:not(:disabled){background:hsla(0,0%,100%,.05);color:#fff}.ai-chat-booking-card{--action-accent:var(--primary-color,#3b82f6);background:var(--bg-secondary,#f9fafb);border:1px solid var(--border-subtle,rgba(0,0,0,.06));border-radius:12px;box-sizing:border-box;margin:6px 0;padding:16px;width:100%}.ai-chat-widget.dark .ai-chat-booking-card,.chakra-ui-dark .ai-chat-booking-card,.dark .ai-chat-booking-card,[data-theme=dark] .ai-chat-booking-card{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__header{align-items:center;display:flex;gap:8px;margin-bottom:12px}.ai-chat-booking-card__icon{flex-shrink:0;font-size:18px}.ai-chat-booking-card__title{color:var(--text-primary,#3e3e3e);font-size:15px;font-weight:600}.ai-chat-widget.dark .ai-chat-booking-card__title,.chakra-ui-dark .ai-chat-booking-card__title,.dark .ai-chat-booking-card__title,[data-theme=dark] .ai-chat-booking-card__title{color:#fff}.ai-chat-booking-card__content{display:flex;flex-direction:column;gap:12px}.ai-chat-booking-card__description{color:var(--text-muted,#71717a);font-size:13px;line-height:1.4;margin:0}.ai-chat-booking-card__empty{color:var(--text-muted,#71717a);font-size:13px;padding:16px;text-align:center}.ai-chat-booking-card__input{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;box-sizing:border-box;color:var(--text-primary,#3e3e3e);font-family:inherit;font-size:14px;outline:none;padding:10px 12px;transition:border-color .2s ease,box-shadow .2s ease;width:100%}.ai-chat-booking-card__input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.1)}.ai-chat-booking-card__input::placeholder{color:var(--text-muted,#9ca3af)}.ai-chat-widget.dark .ai-chat-booking-card__input,.chakra-ui-dark .ai-chat-booking-card__input,.dark .ai-chat-booking-card__input,[data-theme=dark] .ai-chat-booking-card__input{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__input:focus,.chakra-ui-dark .ai-chat-booking-card__input:focus,.dark .ai-chat-booking-card__input:focus,[data-theme=dark] .ai-chat-booking-card__input:focus{border-color:var(--action-accent,var(--primary-color,#3b82f6));box-shadow:0 0 0 3px rgba(59,130,246,.2)}.ai-chat-booking-card__label{color:var(--text-secondary,#6b7280);display:block;font-size:13px;font-weight:500;margin-bottom:4px}.ai-chat-widget.dark .ai-chat-booking-card__label,.chakra-ui-dark .ai-chat-booking-card__label,.dark .ai-chat-booking-card__label,[data-theme=dark] .ai-chat-booking-card__label{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__btn{border:none;border-radius:9999px;box-sizing:border-box;cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:10px 16px;transition:all .2s ease;width:100%}.ai-chat-booking-card__btn:disabled{cursor:not-allowed;opacity:.5}.ai-chat-booking-card__btn--primary{background:var(--action-accent,var(--primary-color,#3b82f6));color:#fff}.ai-chat-booking-card__btn--primary:hover:not(:disabled){opacity:.9;transform:translateY(-1px)}.ai-chat-booking-card__btn--secondary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);color:var(--text-primary,#3e3e3e)}.ai-chat-booking-card__btn--secondary:hover:not(:disabled){border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-booking-card__btn--secondary,.chakra-ui-dark .ai-chat-booking-card__btn--secondary,.dark .ai-chat-booking-card__btn--secondary,[data-theme=dark] .ai-chat-booking-card__btn--secondary{background:hsla(0,0%,100%,.05);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-booking-card__btn--danger{background:rgba(220,38,38,.1);border:1px solid rgba(220,38,38,.2);color:#dc2626}.ai-chat-booking-card__btn--danger:hover:not(:disabled){background:rgba(220,38,38,.15)}.ai-chat-widget.dark .ai-chat-booking-card__btn--danger,.chakra-ui-dark .ai-chat-booking-card__btn--danger,.dark .ai-chat-booking-card__btn--danger,[data-theme=dark] .ai-chat-booking-card__btn--danger{background:rgba(239,68,68,.2);border-color:rgba(239,68,68,.3);color:#fca5a5}.ai-chat-booking-card__grid{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(200px,1fr))}.ai-chat-booking-card__contact{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;cursor:pointer;display:flex;flex-direction:column;font-family:inherit;padding:12px;text-align:left;transition:all .2s ease}.ai-chat-booking-card__contact:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-booking-card__contact--selected{border-width:2px}.ai-chat-widget.dark .ai-chat-booking-card__contact,.chakra-ui-dark .ai-chat-booking-card__contact,.dark .ai-chat-booking-card__contact,[data-theme=dark] .ai-chat-booking-card__contact{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-widget.dark .ai-chat-booking-card__contact--selected,.chakra-ui-dark .ai-chat-booking-card__contact--selected,.dark .ai-chat-booking-card__contact--selected,[data-theme=dark] .ai-chat-booking-card__contact--selected{background:rgba(59,130,246,.15)}.ai-chat-booking-card__contact-name{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__contact-name,.chakra-ui-dark .ai-chat-booking-card__contact-name,.dark .ai-chat-booking-card__contact-name,[data-theme=dark] .ai-chat-booking-card__contact-name{color:#fff}.ai-chat-booking-card__contact-role{color:var(--text-muted,#71717a);font-size:12px;margin-top:2px}.ai-chat-booking-card__options{display:flex;flex-direction:column;gap:8px}.ai-chat-booking-card__option-btn{align-items:center;background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;box-sizing:border-box;cursor:pointer;display:flex;font-family:inherit;gap:12px;padding:12px;text-align:left;transition:all .2s ease;width:100%}.ai-chat-booking-card__option-btn:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-widget.dark .ai-chat-booking-card__option-btn,.chakra-ui-dark .ai-chat-booking-card__option-btn,.dark .ai-chat-booking-card__option-btn,[data-theme=dark] .ai-chat-booking-card__option-btn{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__option-icon{flex-shrink:0;font-size:18px}.ai-chat-booking-card__option-text{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__option-text,.chakra-ui-dark .ai-chat-booking-card__option-text,.dark .ai-chat-booking-card__option-text,[data-theme=dark] .ai-chat-booking-card__option-text{color:#fff}.ai-chat-booking-card__date-group{margin-bottom:12px}.ai-chat-booking-card__date-header{color:var(--text-muted,#71717a);font-size:12px;font-weight:600;letter-spacing:.5px;margin-bottom:8px;text-transform:uppercase}.ai-chat-booking-card__slots{display:grid;gap:8px;grid-template-columns:repeat(auto-fill,minmax(120px,1fr))}.ai-chat-booking-card__slot{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;color:var(--text-primary,#3e3e3e);cursor:pointer;font-family:inherit;font-size:13px;font-weight:500;padding:10px 12px;transition:all .2s ease}.ai-chat-booking-card__slot:hover{background:rgba(59,130,246,.05);border-color:var(--action-accent,var(--primary-color,#3b82f6))}.ai-chat-booking-card__slot--selected{border-width:2px}.ai-chat-widget.dark .ai-chat-booking-card__slot,.chakra-ui-dark .ai-chat-booking-card__slot,.dark .ai-chat-booking-card__slot,[data-theme=dark] .ai-chat-booking-card__slot{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1);color:#fff}.ai-chat-widget.dark .ai-chat-booking-card__slot--selected,.chakra-ui-dark .ai-chat-booking-card__slot--selected,.dark .ai-chat-booking-card__slot--selected,[data-theme=dark] .ai-chat-booking-card__slot--selected{background:rgba(59,130,246,.15)}.ai-chat-booking-card__appointments{display:flex;flex-direction:column;gap:10px}.ai-chat-booking-card__appointment{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;padding:12px}.ai-chat-widget.dark .ai-chat-booking-card__appointment,.chakra-ui-dark .ai-chat-booking-card__appointment,.dark .ai-chat-booking-card__appointment,[data-theme=dark] .ai-chat-booking-card__appointment{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__appointment-header{align-items:center;display:flex;gap:8px;justify-content:space-between;margin-bottom:6px}.ai-chat-booking-card__appointment-subject{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500}.ai-chat-widget.dark .ai-chat-booking-card__appointment-subject,.chakra-ui-dark .ai-chat-booking-card__appointment-subject,.dark .ai-chat-booking-card__appointment-subject,[data-theme=dark] .ai-chat-booking-card__appointment-subject{color:#fff}.ai-chat-booking-card__appointment-status{border-radius:4px;font-size:11px;font-weight:600;padding:2px 6px;text-transform:uppercase}.ai-chat-booking-card__appointment-status--confirmed,.ai-chat-booking-card__appointment-status--pending{background:rgba(34,197,94,.1);color:#16a34a}.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--confirmed,.ai-chat-widget.dark .ai-chat-booking-card__appointment-status--pending,.chakra-ui-dark .ai-chat-booking-card__appointment-status--confirmed,.chakra-ui-dark .ai-chat-booking-card__appointment-status--pending,.dark .ai-chat-booking-card__appointment-status--confirmed,.dark .ai-chat-booking-card__appointment-status--pending,[data-theme=dark] .ai-chat-booking-card__appointment-status--confirmed,[data-theme=dark] .ai-chat-booking-card__appointment-status--pending{background:rgba(34,197,94,.2);color:#4ade80}.ai-chat-booking-card__appointment-status--cancelled{background:hsla(220,9%,46%,.1);color:#6b7280}.ai-chat-booking-card__appointment-time{color:var(--text-secondary,#6b7280);font-size:13px;margin-bottom:4px}.ai-chat-widget.dark .ai-chat-booking-card__appointment-time,.chakra-ui-dark .ai-chat-booking-card__appointment-time,.dark .ai-chat-booking-card__appointment-time,[data-theme=dark] .ai-chat-booking-card__appointment-time{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__appointment-contact{color:var(--text-muted,#71717a);font-size:12px}.ai-chat-booking-card__summary{background:var(--bg-primary,#fff);border:1px solid var(--border-default,#e5e7eb);border-radius:8px;margin-bottom:12px;padding:12px}.ai-chat-widget.dark .ai-chat-booking-card__summary,.chakra-ui-dark .ai-chat-booking-card__summary,.dark .ai-chat-booking-card__summary,[data-theme=dark] .ai-chat-booking-card__summary{background:rgba(0,0,0,.2);border-color:hsla(0,0%,100%,.1)}.ai-chat-booking-card__summary-row{align-items:center;display:flex;justify-content:space-between;padding:6px 0}.ai-chat-booking-card__summary-row:not(:last-child){border-bottom:1px solid var(--border-subtle,rgba(0,0,0,.06))}.ai-chat-widget.dark .ai-chat-booking-card__summary-row:not(:last-child),.chakra-ui-dark .ai-chat-booking-card__summary-row:not(:last-child),.dark .ai-chat-booking-card__summary-row:not(:last-child),[data-theme=dark] .ai-chat-booking-card__summary-row:not(:last-child){border-bottom-color:hsla(0,0%,100%,.08)}.ai-chat-booking-card__summary-label{color:var(--text-muted,#71717a);font-size:12px;font-weight:600;letter-spacing:.5px;text-transform:uppercase}.ai-chat-booking-card__summary-value{color:var(--text-primary,#3e3e3e);font-size:14px;font-weight:500;text-align:right}.ai-chat-widget.dark .ai-chat-booking-card__summary-value,.chakra-ui-dark .ai-chat-booking-card__summary-value,.dark .ai-chat-booking-card__summary-value,[data-theme=dark] .ai-chat-booking-card__summary-value{color:#fff}.ai-chat-booking-card__link{display:inline-block;font-size:13px;font-weight:500;margin-top:8px;text-decoration:none;transition:opacity .2s ease}.ai-chat-booking-card__link:hover{opacity:.8;text-decoration:underline}.ai-chat-booking-card--success{background:rgba(34,197,94,.05);border-color:rgba(34,197,94,.2)}.ai-chat-widget.dark .ai-chat-booking-card--success,.chakra-ui-dark .ai-chat-booking-card--success,.dark .ai-chat-booking-card--success,[data-theme=dark] .ai-chat-booking-card--success{background:rgba(34,197,94,.1);border-color:rgba(34,197,94,.3)}.ai-chat-booking-card--pending{background:rgba(234,179,8,.05);border-color:rgba(234,179,8,.2)}.ai-chat-widget.dark .ai-chat-booking-card--pending,.chakra-ui-dark .ai-chat-booking-card--pending,.dark .ai-chat-booking-card--pending,[data-theme=dark] .ai-chat-booking-card--pending{background:rgba(234,179,8,.1);border-color:rgba(234,179,8,.3)}.ai-chat-booking-card--cancelled{background:hsla(220,9%,46%,.05);border-color:hsla(220,9%,46%,.2)}.ai-chat-widget.dark .ai-chat-booking-card--cancelled,.chakra-ui-dark .ai-chat-booking-card--cancelled,.dark .ai-chat-booking-card--cancelled,[data-theme=dark] .ai-chat-booking-card--cancelled{background:hsla(220,9%,46%,.1);border-color:hsla(220,9%,46%,.3)}.ai-chat-booking-card--error{background:rgba(239,68,68,.05);border-color:rgba(239,68,68,.2)}.ai-chat-widget.dark .ai-chat-booking-card--error,.chakra-ui-dark .ai-chat-booking-card--error,.dark .ai-chat-booking-card--error,[data-theme=dark] .ai-chat-booking-card--error{background:rgba(239,68,68,.1);border-color:rgba(239,68,68,.3)}.ai-chat-booking-card__pending-text,.ai-chat-booking-card__success-text{color:var(--text-secondary,#6b7280);font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-booking-card__pending-text,.ai-chat-widget.dark .ai-chat-booking-card__success-text,.chakra-ui-dark .ai-chat-booking-card__pending-text,.chakra-ui-dark .ai-chat-booking-card__success-text,.dark .ai-chat-booking-card__pending-text,.dark .ai-chat-booking-card__success-text,[data-theme=dark] .ai-chat-booking-card__pending-text,[data-theme=dark] .ai-chat-booking-card__success-text{color:var(--text-secondary,#a1a1aa)}.ai-chat-booking-card__error{color:#dc2626;font-size:13px;margin:0}.ai-chat-widget.dark .ai-chat-booking-card__error,.chakra-ui-dark .ai-chat-booking-card__error,.dark .ai-chat-booking-card__error,[data-theme=dark] .ai-chat-booking-card__error{color:#fca5a5}.chat-fullpage{--fp-max-width:800px;--fp-padding-x:16px;--fp-padding-top-mobile:64px;--fp-padding-top-desktop:16px;--fp-padding-bottom:200px;--fp-input-bottom:0}.chat-fullpage .ai-chat-messages{background:transparent;height:100%;margin:0 auto;max-width:var(--fp-max-width);padding:var(--fp-padding-top-desktop) var(--fp-padding-x) var(--fp-padding-bottom)}@media (max-width:768px){.chat-fullpage .ai-chat-messages{padding-top:var(--fp-padding-top-mobile)}}.chat-fullpage .ai-chat-message{animation:none}.chat-fullpage .ai-chat-message.user{max-width:85%}.chat-fullpage .ai-chat-message.user .ai-chat-message-content{background:var(--bg-muted,#f4f4f5);border-radius:24px;color:#000;padding:8px 16px}.chat-fullpage.dark .ai-chat-message.user .ai-chat-message-content{background:var(--bg-muted,#27272a);color:#fff}.chat-fullpage .ai-chat-message.assistant{width:100%}.chat-fullpage .ai-chat-message.assistant .ai-chat-message-content{color:#000;padding:8px 16px}.chat-fullpage.dark .ai-chat-message.assistant .ai-chat-message-content{color:#fff}.chat-fullpage .ai-chat-message.tool{margin:0;padding:0;width:100%}.chat-fullpage .ai-chat-welcome{align-items:center;display:flex;flex-direction:column;gap:24px;justify-content:center;min-height:60vh;padding:24px;text-align:center}.chat-fullpage .ai-chat-welcome-title{font-size:32px;font-weight:600}.chat-fullpage .ai-chat-welcome-text{color:var(--text-muted,#71717a);font-size:18px;max-width:400px}.chat-fullpage .ai-chat-input-container{background:transparent;bottom:0;left:0;padding:16px 16px calc(16px + env(safe-area-inset-bottom));position:fixed;right:0;z-index:20}.chat-fullpage .ai-chat-input-container:after{background:var(--bg-primary,#fff);bottom:0;content:\"\";height:calc(40% + 16px);left:0;pointer-events:none;position:absolute;right:0;z-index:-1}.chat-fullpage.dark .ai-chat-input-container:after{background:var(--bg-primary,#18181b)}@media (min-width:769px){.chat-fullpage .ai-chat-input-container{background:transparent;bottom:var(--fp-input-bottom);left:50%;max-width:var(--fp-max-width);padding:0;position:absolute;right:auto;transform:translateX(-50%);width:100%}}.chat-fullpage .ai-chat-input-wrapper{background:var(--bg-muted,#f4f4f5);border:1px solid var(--border-muted,#e4e4e7);border-radius:24px;box-shadow:0 1px 8px rgba(0,0,0,.06);margin:0 auto;max-width:var(--fp-max-width)}.chat-fullpage.dark .ai-chat-input-wrapper{background:var(--bg-muted,#27272a);border-color:var(--border-muted,#3f3f46);box-shadow:0 1px 12px rgba(0,0,0,.25)}.chat-fullpage .ai-chat-scroll-button{bottom:100px}@media (min-width:769px){.chat-fullpage .ai-chat-scroll-button{bottom:90px}}.chat-fullpage .ai-chat-suggested-questions{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;max-width:600px}.chat-fullpage .ai-chat-suggested-question{border-radius:9999px;font-size:14px;padding:8px 16px}.chat-fullpage .ai-chat-follow-up-suggestions{margin-top:12px}.chat-fullpage .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-default,#d4d4d8);color:#000}.chat-fullpage .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#f4f4f5)}.chat-fullpage.dark .ai-chat-follow-up-item.question-type{background:transparent;border:1px solid var(--border-subtle,#52525b);color:#fff}.chat-fullpage.dark .ai-chat-follow-up-item.question-type:hover{background:var(--bg-hover,#3f3f46)}.chat-fullpage .ai-chat-typing{padding:8px 16px}@media (max-width:480px){body.ai-chat-widget-open{height:100%!important;overflow:hidden!important;position:fixed!important;touch-action:none!important;width:100%!important}.ai-chat-widget-container.is-open{height:100vh!important;height:100dvh!important;width:100vw!important;z-index:var(--widget-z-index,2147483647)!important}.ai-chat-widget-container.is-open,.ai-chat-widget-container.is-open .ai-chat-window{bottom:0!important;left:0!important;position:fixed!important;right:0!important;top:0!important}.ai-chat-widget-container.is-open .ai-chat-window{animation:none!important;border:none!important;border-radius:0!important;box-shadow:none!important;height:100%!important;max-height:100%!important;max-width:100%!important;outline:none!important;transform:none!important;width:100%!important}.ai-chat-widget-container.is-open .ai-chat-button{display:none!important;pointer-events:none!important;visibility:hidden!important}.ai-chat-widget-container.is-open .ai-chat-header{border-radius:0!important;flex-shrink:0;padding-left:max(16px,env(safe-area-inset-left));padding-right:max(16px,env(safe-area-inset-right));padding-top:max(12px,env(safe-area-inset-top));position:relative;z-index:100}.ai-chat-widget-container.is-open .ai-chat-messages{-webkit-overflow-scrolling:touch;flex:1;overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;padding-bottom:120px;padding-left:max(16px,env(safe-area-inset-left));padding-right:max(16px,env(safe-area-inset-right));touch-action:pan-y}.ai-chat-widget-container.is-open .ai-chat-input-container{background:var(--bg-primary,#fff);bottom:0!important;left:0!important;padding:8px max(12px,env(safe-area-inset-right)) max(16px,calc(env(safe-area-inset-bottom) + 8px)) max(12px,env(safe-area-inset-left));position:fixed!important;right:0!important;z-index:100}.ai-chat-widget.dark .ai-chat-widget-container.is-open .ai-chat-input-container{background:var(--bg-primary,#282625)}.ai-chat-widget-container.is-open .ai-chat-input-container:after{display:none}.ai-chat-widget-container.is-open .ai-chat-input-wrapper{margin:0;max-width:100%}.ai-chat-widget-container.is-open .ai-chat-scroll-button{bottom:calc(80px + env(safe-area-inset-bottom))}.ai-chat-widget-container.is-open .ai-chat-welcome{padding:16px 0}.ai-chat-widget-container.is-open .ai-chat-welcome-title{font-size:24px}.ai-chat-widget-container.is-open .ai-chat-suggested-questions{align-items:stretch;flex-direction:column}.ai-chat-widget-container.is-open .ai-chat-suggested-question{text-align:center;width:100%}}@media (min-width:481px) and (max-width:768px){.ai-chat-widget-container.is-open .ai-chat-window{border-radius:22px 22px 44px 44px;max-height:calc(100vh - 100px);max-width:calc(100vw - 32px)}}";
|
|
47531
|
+
styleInject(css_248z$1);
|
|
47532
|
+
|
|
47533
|
+
var css_248z = ".ai-chat-data-policy-view{display:flex;flex:1;flex-direction:column;min-height:0;overflow:hidden}.ai-chat-data-policy-content{-webkit-overflow-scrolling:touch;flex:1;overflow-y:auto;padding:20px 16px 40px}.ai-chat-data-policy-intro{margin-bottom:24px}.ai-chat-data-policy-intro p{color:var(--text-primary,#18181b);font-size:13px;line-height:1.6;margin:0;text-align:left}.ai-chat-widget.dark .ai-chat-data-policy-intro p{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-intro strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-intro strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section{margin-bottom:20px}.ai-chat-data-policy-section h3{color:var(--text-primary,#18181b);font-size:14px;font-weight:600;margin:0 0 12px}.ai-chat-widget.dark .ai-chat-data-policy-section h3{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p{color:var(--text-secondary,#52525b);font-size:12px;line-height:1.6;margin:0 0 12px;text-align:justify;text-justify:inter-word}.ai-chat-widget.dark .ai-chat-data-policy-section p{color:var(--text-secondary,#a1a1aa)}.ai-chat-data-policy-section p strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-section p strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p:last-child{margin-bottom:0}";
|
|
46372
47534
|
styleInject(css_248z);
|
|
46373
47535
|
|
|
46374
47536
|
// Icon components mapping
|
|
@@ -46376,11 +47538,23 @@
|
|
|
46376
47538
|
FiMessageCircle: () => (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.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" }) })),
|
|
46377
47539
|
FiChevronDown: () => (jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "6 9 12 15 18 9" }) })),
|
|
46378
47540
|
};
|
|
46379
|
-
const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
|
|
47541
|
+
const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, demoMode = false, demoInput, demoOutput, onDemoComplete, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, triggerType, triggerText, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, containerMode = false, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
|
|
46380
47542
|
const [isOpen, setIsOpen] = reactExports.useState(defaultOpen);
|
|
47543
|
+
const [inputBarValue, setInputBarValue] = reactExports.useState('');
|
|
46381
47544
|
const [autoDetectedTheme, setAutoDetectedTheme] = reactExports.useState('light');
|
|
47545
|
+
const [showWelcomeBubble, setShowWelcomeBubble] = reactExports.useState(false);
|
|
46382
47546
|
const widgetRef = reactExports.useRef(null);
|
|
46383
47547
|
const containerRef = reactExports.useRef(null);
|
|
47548
|
+
// Demo mode state - track whether demo has been activated and completed
|
|
47549
|
+
const [demoMessages, setDemoMessages] = reactExports.useState([]);
|
|
47550
|
+
const [isDemoComplete, setIsDemoComplete] = reactExports.useState(false);
|
|
47551
|
+
const [isDemoTyping, setIsDemoTyping] = reactExports.useState(false);
|
|
47552
|
+
const [demoInputBarText, setDemoInputBarText] = reactExports.useState(''); // For animating text in input bar
|
|
47553
|
+
const [isDemoAnimatingInput, setIsDemoAnimatingInput] = reactExports.useState(false); // True while typing into input bar
|
|
47554
|
+
const [isDemoActive, setIsDemoActive] = reactExports.useState(false); // True when demo animation is running
|
|
47555
|
+
const demoStartedRef = reactExports.useRef(false);
|
|
47556
|
+
// Track if user has sent a real message (transitions from demo to real chat)
|
|
47557
|
+
const [userSentRealMessage, setUserSentRealMessage] = reactExports.useState(false);
|
|
46384
47558
|
// Determine mode
|
|
46385
47559
|
const isEmbedded = mode === 'embedded';
|
|
46386
47560
|
// Default config for preview mode
|
|
@@ -46400,6 +47574,7 @@
|
|
|
46400
47574
|
showChatHistory: true,
|
|
46401
47575
|
showTimestamps: true,
|
|
46402
47576
|
showTypingIndicator: true,
|
|
47577
|
+
showToolCalls: false,
|
|
46403
47578
|
enableFileUpload: false,
|
|
46404
47579
|
enableFeedback: true,
|
|
46405
47580
|
},
|
|
@@ -46425,29 +47600,54 @@
|
|
|
46425
47600
|
...previewConfig?.behavior,
|
|
46426
47601
|
},
|
|
46427
47602
|
};
|
|
46428
|
-
// Always call useChat hook (React rules), but skip initialization in preview mode
|
|
47603
|
+
// Always call useChat hook (React rules), but skip initialization in preview mode or during demo
|
|
47604
|
+
// Skip initialization during demo to prevent loading old conversations
|
|
47605
|
+
// Note: We still pass the real widgetId so createDemoConversation works correctly
|
|
47606
|
+
const shouldSkipInit = previewMode || (demoMode && !userSentRealMessage);
|
|
46429
47607
|
const chatHook = useChat({
|
|
46430
47608
|
widgetId: previewMode ? '__preview__' : (widgetId || '__preview__'),
|
|
46431
47609
|
apiUrl,
|
|
46432
47610
|
currentRoute,
|
|
46433
|
-
onMessage:
|
|
46434
|
-
onError:
|
|
46435
|
-
skipInitialization:
|
|
47611
|
+
onMessage: shouldSkipInit ? undefined : onMessage,
|
|
47612
|
+
onError: shouldSkipInit ? undefined : onError,
|
|
47613
|
+
skipInitialization: shouldSkipInit, // Don't make API calls in preview mode or during demo
|
|
46436
47614
|
});
|
|
46437
47615
|
// Extract values from hook or use preview defaults
|
|
46438
|
-
const
|
|
46439
|
-
const
|
|
46440
|
-
const
|
|
46441
|
-
const error = previewMode ? null : chatHook.error;
|
|
47616
|
+
const hookMessages = previewMode ? [] : chatHook.messages;
|
|
47617
|
+
const hookIsLoading = previewMode ? false : chatHook.isLoading;
|
|
47618
|
+
const hookIsTyping = previewMode ? false : chatHook.isTyping;
|
|
46442
47619
|
const config = previewMode ? mergedPreviewConfig : chatHook.config;
|
|
46443
|
-
const
|
|
47620
|
+
const hookSendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
|
|
46444
47621
|
const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
|
|
47622
|
+
const dismissAction = previewMode ? (() => Promise.resolve()) : chatHook.dismissAction;
|
|
46445
47623
|
const conversations = previewMode ? [] : chatHook.conversations;
|
|
46446
47624
|
const loadConversations = previewMode ? (() => { }) : chatHook.loadConversations;
|
|
46447
47625
|
const switchConversation = previewMode ? (() => Promise.resolve()) : chatHook.switchConversation;
|
|
46448
47626
|
const startNewConversation = previewMode ? (() => { }) : chatHook.startNewConversation;
|
|
46449
47627
|
const deleteConversation = previewMode ? (() => { }) : chatHook.deleteConversation;
|
|
47628
|
+
const createDemoConversation = previewMode ? (() => Promise.resolve(null)) : chatHook.createDemoConversation;
|
|
46450
47629
|
const conversationId = previewMode ? '' : chatHook.conversationId;
|
|
47630
|
+
// Message display logic:
|
|
47631
|
+
// - During demo (before user sends real message): show demoMessages
|
|
47632
|
+
// - After user sends real message: show hookMessages
|
|
47633
|
+
const showDemoMessages = demoMode && demoMessages.length > 0 && !userSentRealMessage;
|
|
47634
|
+
const messages = showDemoMessages ? demoMessages : hookMessages;
|
|
47635
|
+
const isLoading = showDemoMessages ? false : hookIsLoading;
|
|
47636
|
+
const isTyping = showDemoMessages ? isDemoTyping : hookIsTyping;
|
|
47637
|
+
// Send message handler - transitions from demo to real chat when user sends first message
|
|
47638
|
+
const sendMessage = reactExports.useCallback((content) => {
|
|
47639
|
+
if (demoMode && isDemoActive && !isDemoComplete) {
|
|
47640
|
+
// Demo animation is still running - ignore user input
|
|
47641
|
+
return Promise.resolve();
|
|
47642
|
+
}
|
|
47643
|
+
// User is sending a real message - transition to real chat
|
|
47644
|
+
if (demoMode && !userSentRealMessage) {
|
|
47645
|
+
setUserSentRealMessage(true);
|
|
47646
|
+
// Clear demo messages so hook messages take over
|
|
47647
|
+
setDemoMessages([]);
|
|
47648
|
+
}
|
|
47649
|
+
return hookSendMessage(content);
|
|
47650
|
+
}, [demoMode, isDemoActive, isDemoComplete, userSentRealMessage, hookSendMessage]);
|
|
46451
47651
|
// Auto-detect theme from background
|
|
46452
47652
|
reactExports.useEffect(() => {
|
|
46453
47653
|
if (!containerRef.current)
|
|
@@ -46473,8 +47673,16 @@
|
|
|
46473
47673
|
mediaQuery.removeEventListener('change', handleMediaChange);
|
|
46474
47674
|
};
|
|
46475
47675
|
}, [config]);
|
|
46476
|
-
//
|
|
47676
|
+
// Check if device is mobile
|
|
47677
|
+
const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
|
|
47678
|
+
// Handle auto-open (only for bubble mode, disabled on mobile)
|
|
46477
47679
|
reactExports.useEffect(() => {
|
|
47680
|
+
// Never auto-open on mobile devices
|
|
47681
|
+
if (isMobile)
|
|
47682
|
+
return undefined;
|
|
47683
|
+
// Don't auto-open if demo mode is active - let demo animation control opening
|
|
47684
|
+
if (demoMode && !isDemoComplete)
|
|
47685
|
+
return undefined;
|
|
46478
47686
|
if (!isEmbedded && config?.settings.autoOpen) {
|
|
46479
47687
|
const delay = config.settings.autoOpenDelay || 0;
|
|
46480
47688
|
const timer = setTimeout(() => {
|
|
@@ -46484,7 +47692,7 @@
|
|
|
46484
47692
|
return () => clearTimeout(timer);
|
|
46485
47693
|
}
|
|
46486
47694
|
return undefined;
|
|
46487
|
-
}, [config, onOpen, isEmbedded]);
|
|
47695
|
+
}, [config, onOpen, isEmbedded, isMobile, demoMode, isDemoComplete]);
|
|
46488
47696
|
// Handle close on Escape key (only for bubble mode)
|
|
46489
47697
|
reactExports.useEffect(() => {
|
|
46490
47698
|
if (!isOpen || isEmbedded)
|
|
@@ -46498,6 +47706,203 @@
|
|
|
46498
47706
|
document.addEventListener('keydown', handleEscapeKey);
|
|
46499
47707
|
return () => document.removeEventListener('keydown', handleEscapeKey);
|
|
46500
47708
|
}, [isOpen, onClose, isEmbedded]);
|
|
47709
|
+
// Handle body scroll lock on mobile when widget is open
|
|
47710
|
+
reactExports.useEffect(() => {
|
|
47711
|
+
if (!isOpen || isEmbedded)
|
|
47712
|
+
return;
|
|
47713
|
+
// Only apply scroll lock on mobile
|
|
47714
|
+
const checkMobile = window.innerWidth <= 480;
|
|
47715
|
+
if (!checkMobile)
|
|
47716
|
+
return;
|
|
47717
|
+
// Add class to body to lock scrolling
|
|
47718
|
+
document.body.classList.add('ai-chat-widget-open');
|
|
47719
|
+
return () => {
|
|
47720
|
+
document.body.classList.remove('ai-chat-widget-open');
|
|
47721
|
+
};
|
|
47722
|
+
}, [isOpen, isEmbedded]);
|
|
47723
|
+
// Handle welcome bubble visibility based on frequency setting
|
|
47724
|
+
// Frequency options: 'always' (every page visit), 'session', 'weekly', 'monthly'
|
|
47725
|
+
reactExports.useEffect(() => {
|
|
47726
|
+
if (isEmbedded || previewMode)
|
|
47727
|
+
return;
|
|
47728
|
+
const bubbleText = welcomeBubbleText ?? config?.appearance?.welcomeBubbleText;
|
|
47729
|
+
if (!bubbleText) {
|
|
47730
|
+
setShowWelcomeBubble(false);
|
|
47731
|
+
return;
|
|
47732
|
+
}
|
|
47733
|
+
const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
|
|
47734
|
+
const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
|
|
47735
|
+
// Check if bubble should be shown based on frequency
|
|
47736
|
+
const shouldShowBubble = () => {
|
|
47737
|
+
if (frequency === 'always') {
|
|
47738
|
+
// Always show on every page visit (no storage check)
|
|
47739
|
+
return true;
|
|
47740
|
+
}
|
|
47741
|
+
if (frequency === 'session') {
|
|
47742
|
+
// Show once per session
|
|
47743
|
+
return sessionStorage.getItem(storageKey) !== 'true';
|
|
47744
|
+
}
|
|
47745
|
+
// For weekly/monthly, use localStorage with timestamp
|
|
47746
|
+
try {
|
|
47747
|
+
const stored = localStorage.getItem(storageKey);
|
|
47748
|
+
if (!stored)
|
|
47749
|
+
return true;
|
|
47750
|
+
const dismissedAt = parseInt(stored, 10);
|
|
47751
|
+
if (isNaN(dismissedAt))
|
|
47752
|
+
return true;
|
|
47753
|
+
const now = Date.now();
|
|
47754
|
+
const weekMs = 7 * 24 * 60 * 60 * 1000;
|
|
47755
|
+
const monthMs = 30 * 24 * 60 * 60 * 1000;
|
|
47756
|
+
if (frequency === 'weekly') {
|
|
47757
|
+
return now - dismissedAt > weekMs;
|
|
47758
|
+
}
|
|
47759
|
+
if (frequency === 'monthly') {
|
|
47760
|
+
return now - dismissedAt > monthMs;
|
|
47761
|
+
}
|
|
47762
|
+
}
|
|
47763
|
+
catch {
|
|
47764
|
+
return true;
|
|
47765
|
+
}
|
|
47766
|
+
return true;
|
|
47767
|
+
};
|
|
47768
|
+
if (shouldShowBubble() && !isOpen) {
|
|
47769
|
+
setShowWelcomeBubble(true);
|
|
47770
|
+
}
|
|
47771
|
+
}, [widgetId, welcomeBubbleText, config, isOpen, isEmbedded, previewMode]);
|
|
47772
|
+
// Demo mode: animate typing into input bar, then open widget with conversation
|
|
47773
|
+
// This shows the widget in action without making expensive AI calls
|
|
47774
|
+
reactExports.useEffect(() => {
|
|
47775
|
+
// Determine trigger type early (from prop or config)
|
|
47776
|
+
// IMPORTANT: For demo mode, we need config to be loaded to know the trigger type
|
|
47777
|
+
// If config is not loaded yet, wait for it (unless triggerType prop is provided)
|
|
47778
|
+
const effectiveTriggerTypeForDemo = triggerType ?? config?.appearance?.triggerType ?? 'button';
|
|
47779
|
+
const isInputBarTrigger = effectiveTriggerTypeForDemo === 'input-bar';
|
|
47780
|
+
// Debug logging
|
|
47781
|
+
console.log('[Widget] Demo effect check:', {
|
|
47782
|
+
demoMode,
|
|
47783
|
+
isDemoComplete,
|
|
47784
|
+
demoStartedRef: demoStartedRef.current,
|
|
47785
|
+
hasDemoInput: !!demoInput,
|
|
47786
|
+
hasDemoOutput: !!demoOutput,
|
|
47787
|
+
triggerType: effectiveTriggerTypeForDemo,
|
|
47788
|
+
isInputBar: isInputBarTrigger,
|
|
47789
|
+
isOpen,
|
|
47790
|
+
});
|
|
47791
|
+
// Start demo when demoMode is enabled and we have input/output
|
|
47792
|
+
const shouldStartDemo = demoMode && !isDemoComplete && !demoStartedRef.current && demoInput && demoOutput;
|
|
47793
|
+
if (!shouldStartDemo) {
|
|
47794
|
+
console.log('[Widget] Demo not starting:', { shouldStartDemo, reason: !demoMode ? 'demoMode false' : !demoInput ? 'no demoInput' : !demoOutput ? 'no demoOutput' : isDemoComplete ? 'already complete' : demoStartedRef.current ? 'already started' : 'unknown' });
|
|
47795
|
+
return;
|
|
47796
|
+
}
|
|
47797
|
+
// Wait for config to load before starting demo (unless triggerType prop is explicitly provided)
|
|
47798
|
+
// This prevents the demo from starting with wrong trigger type
|
|
47799
|
+
if (!triggerType && !config) {
|
|
47800
|
+
console.log('[Widget] Demo waiting for config or triggerType prop');
|
|
47801
|
+
return;
|
|
47802
|
+
}
|
|
47803
|
+
// For input-bar: start immediately (widget closed, type into bar)
|
|
47804
|
+
// For others: wait until widget is open
|
|
47805
|
+
if (!isInputBarTrigger && !isOpen) {
|
|
47806
|
+
console.log('[Widget] Demo waiting for widget to open (non-input-bar trigger)');
|
|
47807
|
+
return;
|
|
47808
|
+
}
|
|
47809
|
+
console.log('[Widget] Starting demo animation...', {
|
|
47810
|
+
triggerType: effectiveTriggerTypeForDemo,
|
|
47811
|
+
isInputBar: isInputBarTrigger,
|
|
47812
|
+
demoInput,
|
|
47813
|
+
demoOutput: demoOutput?.substring(0, 50) + '...',
|
|
47814
|
+
});
|
|
47815
|
+
demoStartedRef.current = true;
|
|
47816
|
+
setIsDemoActive(true);
|
|
47817
|
+
// Use stable IDs to prevent React from remounting components
|
|
47818
|
+
const userMessageId = 'demo-user-message';
|
|
47819
|
+
const assistantMessageId = 'demo-assistant-message';
|
|
47820
|
+
// Helper to create a message with stable ID
|
|
47821
|
+
const createMessage = (id, role, content, isStreaming = false) => ({
|
|
47822
|
+
id,
|
|
47823
|
+
message: { role, content },
|
|
47824
|
+
timestamp: new Date().toISOString(),
|
|
47825
|
+
sources: [],
|
|
47826
|
+
isStreaming,
|
|
47827
|
+
});
|
|
47828
|
+
// Animation sequence - runs to completion even if widget is closed
|
|
47829
|
+
// This ensures conversation is always created and saved consistently
|
|
47830
|
+
const runDemoAnimation = async () => {
|
|
47831
|
+
// STEP 1: Create conversation IMMEDIATELY at the start
|
|
47832
|
+
// This ensures we have a conversation ID before any animation
|
|
47833
|
+
console.log('[Widget] Creating demo conversation at start...');
|
|
47834
|
+
let conversationId = null;
|
|
47835
|
+
try {
|
|
47836
|
+
conversationId = await createDemoConversation(demoInput, demoOutput);
|
|
47837
|
+
if (conversationId) {
|
|
47838
|
+
console.log('[Widget] Demo conversation created:', conversationId);
|
|
47839
|
+
}
|
|
47840
|
+
}
|
|
47841
|
+
catch (err) {
|
|
47842
|
+
console.warn('[Widget] Failed to create demo conversation:', err);
|
|
47843
|
+
}
|
|
47844
|
+
// STEP 2: For input-bar trigger, animate typing into input bar first
|
|
47845
|
+
if (isInputBarTrigger && !isOpen) {
|
|
47846
|
+
setIsDemoAnimatingInput(true);
|
|
47847
|
+
// Wait before starting to type - ensure input bar is fully visible
|
|
47848
|
+
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
47849
|
+
// Type into input bar character by character
|
|
47850
|
+
const inputChars = demoInput.split('');
|
|
47851
|
+
for (let i = 0; i < inputChars.length; i++) {
|
|
47852
|
+
setDemoInputBarText(demoInput.slice(0, i + 1));
|
|
47853
|
+
// Slower typing speed for better visibility
|
|
47854
|
+
const delay = inputChars[i] === ' ' ? 100 : 60 + Math.random() * 40;
|
|
47855
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
47856
|
+
}
|
|
47857
|
+
// Longer pause after typing so user can read the question
|
|
47858
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
47859
|
+
setIsDemoAnimatingInput(false);
|
|
47860
|
+
setDemoInputBarText('');
|
|
47861
|
+
setIsOpen(true);
|
|
47862
|
+
onOpen?.();
|
|
47863
|
+
// Let widget open animation complete
|
|
47864
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
47865
|
+
}
|
|
47866
|
+
else {
|
|
47867
|
+
// For non-input-bar triggers, just wait for widget to settle
|
|
47868
|
+
await new Promise(resolve => setTimeout(resolve, 800));
|
|
47869
|
+
}
|
|
47870
|
+
// STEP 3: Add user message
|
|
47871
|
+
setDemoMessages([createMessage(userMessageId, 'user', demoInput)]);
|
|
47872
|
+
// Show typing indicator after a pause
|
|
47873
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
47874
|
+
setIsDemoTyping(true);
|
|
47875
|
+
// "Thinking" pause
|
|
47876
|
+
await new Promise(resolve => setTimeout(resolve, 1200));
|
|
47877
|
+
setIsDemoTyping(false);
|
|
47878
|
+
// STEP 4: Stream the response character by character
|
|
47879
|
+
const chars = demoOutput.split('');
|
|
47880
|
+
let currentText = '';
|
|
47881
|
+
// Initial message with empty content
|
|
47882
|
+
setDemoMessages([
|
|
47883
|
+
createMessage(userMessageId, 'user', demoInput),
|
|
47884
|
+
createMessage(assistantMessageId, 'assistant', '', true),
|
|
47885
|
+
]);
|
|
47886
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
47887
|
+
// Stream characters - continues even if widget is closed
|
|
47888
|
+
for (let i = 0; i < chars.length; i++) {
|
|
47889
|
+
currentText += chars[i];
|
|
47890
|
+
setDemoMessages([
|
|
47891
|
+
createMessage(userMessageId, 'user', demoInput),
|
|
47892
|
+
createMessage(assistantMessageId, 'assistant', currentText, i < chars.length - 1),
|
|
47893
|
+
]);
|
|
47894
|
+
const delay = chars[i] === ' ' ? 12 : 20;
|
|
47895
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
47896
|
+
}
|
|
47897
|
+
// STEP 5: Mark demo complete
|
|
47898
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
47899
|
+
setIsDemoComplete(true);
|
|
47900
|
+
setIsDemoActive(false);
|
|
47901
|
+
console.log('[Widget] Demo animation complete');
|
|
47902
|
+
onDemoComplete?.();
|
|
47903
|
+
};
|
|
47904
|
+
runDemoAnimation();
|
|
47905
|
+
}, [demoMode, isOpen, isDemoComplete, demoInput, demoOutput, onDemoComplete, triggerType, config?.appearance?.triggerType, onOpen, createDemoConversation]);
|
|
46501
47906
|
// Determine theme - use prop override if provided, otherwise auto-detect
|
|
46502
47907
|
const appearanceConfig = config?.appearance;
|
|
46503
47908
|
const effectiveTheme = theme ?? autoDetectedTheme;
|
|
@@ -46506,11 +47911,14 @@
|
|
|
46506
47911
|
// Get accent color from prop or config (empty string means no accent color / vanilla mode)
|
|
46507
47912
|
const accentColor = primaryColor ?? appearanceConfig?.primaryColor ?? '';
|
|
46508
47913
|
// Apply prop overrides for live preview (props take priority over config)
|
|
46509
|
-
size || appearanceConfig?.size || 'small';
|
|
47914
|
+
const effectiveSize = size || appearanceConfig?.size || 'small';
|
|
46510
47915
|
const effectiveHeaderTitle = headerTitle ?? appearanceConfig?.headerTitle ?? '';
|
|
46511
47916
|
const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
|
|
46512
47917
|
const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
|
|
46513
47918
|
const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
|
|
47919
|
+
const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
|
|
47920
|
+
const effectiveTriggerType = triggerType ?? appearanceConfig?.triggerType ?? 'button';
|
|
47921
|
+
const effectiveTriggerText = triggerText ?? appearanceConfig?.triggerText ?? 'Chat';
|
|
46514
47922
|
// Generate styles using simplified theme system
|
|
46515
47923
|
const simpleAppearance = {
|
|
46516
47924
|
accentColor};
|
|
@@ -46527,18 +47935,65 @@
|
|
|
46527
47935
|
...customStyles,
|
|
46528
47936
|
...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
|
|
46529
47937
|
};
|
|
47938
|
+
// Dismiss bubble and store based on frequency setting
|
|
47939
|
+
const dismissBubble = () => {
|
|
47940
|
+
setShowWelcomeBubble(false);
|
|
47941
|
+
const frequency = config?.appearance?.welcomeBubbleFrequency ?? 'session';
|
|
47942
|
+
const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
|
|
47943
|
+
try {
|
|
47944
|
+
if (frequency === 'always') {
|
|
47945
|
+
// For 'always', use sessionStorage so it only hides until page refresh
|
|
47946
|
+
sessionStorage.setItem(storageKey, 'true');
|
|
47947
|
+
}
|
|
47948
|
+
else if (frequency === 'session') {
|
|
47949
|
+
sessionStorage.setItem(storageKey, 'true');
|
|
47950
|
+
}
|
|
47951
|
+
else {
|
|
47952
|
+
// For weekly/monthly, store timestamp in localStorage
|
|
47953
|
+
localStorage.setItem(storageKey, String(Date.now()));
|
|
47954
|
+
}
|
|
47955
|
+
}
|
|
47956
|
+
catch {
|
|
47957
|
+
// Ignore storage errors
|
|
47958
|
+
}
|
|
47959
|
+
};
|
|
46530
47960
|
const handleToggle = () => {
|
|
46531
47961
|
if (isEmbedded)
|
|
46532
47962
|
return;
|
|
46533
47963
|
const newState = !isOpen;
|
|
46534
47964
|
setIsOpen(newState);
|
|
47965
|
+
// Dismiss welcome bubble when chat is opened
|
|
47966
|
+
if (newState && showWelcomeBubble) {
|
|
47967
|
+
dismissBubble();
|
|
47968
|
+
}
|
|
46535
47969
|
if (newState) {
|
|
46536
47970
|
onOpen?.();
|
|
46537
47971
|
}
|
|
46538
47972
|
else {
|
|
47973
|
+
// Demo animation continues in background when widget is closed
|
|
47974
|
+
// The conversation was already created at the start, so closing is safe
|
|
47975
|
+
// When user reopens, they'll see the current state of the demo animation
|
|
46539
47976
|
onClose?.();
|
|
46540
47977
|
}
|
|
46541
47978
|
};
|
|
47979
|
+
const handleDismissBubble = (e) => {
|
|
47980
|
+
e.stopPropagation();
|
|
47981
|
+
dismissBubble();
|
|
47982
|
+
};
|
|
47983
|
+
// Handle input bar submit - opens widget and sends message
|
|
47984
|
+
const handleInputBarSubmit = reactExports.useCallback((e) => {
|
|
47985
|
+
e.preventDefault();
|
|
47986
|
+
if (!inputBarValue.trim() || previewMode)
|
|
47987
|
+
return;
|
|
47988
|
+
// Open the widget
|
|
47989
|
+
setIsOpen(true);
|
|
47990
|
+
onOpen?.();
|
|
47991
|
+
// Send the message after a brief delay to allow widget to open
|
|
47992
|
+
setTimeout(() => {
|
|
47993
|
+
sendMessage(inputBarValue.trim());
|
|
47994
|
+
setInputBarValue('');
|
|
47995
|
+
}, 100);
|
|
47996
|
+
}, [inputBarValue, previewMode, onOpen, sendMessage]);
|
|
46542
47997
|
const handleFeedback = async (messageId, feedback) => {
|
|
46543
47998
|
await submitFeedback(messageId, feedback);
|
|
46544
47999
|
};
|
|
@@ -46554,21 +48009,32 @@
|
|
|
46554
48009
|
sendMessage(actionInstruction);
|
|
46555
48010
|
};
|
|
46556
48011
|
// Don't render until config is loaded to avoid flash of unstyled content
|
|
48012
|
+
// Exception: If we have essential props (triggerType), allow rendering the trigger immediately
|
|
48013
|
+
// This improves perceived loading speed - users see the trigger while config loads
|
|
46557
48014
|
// In preview mode, config is always available
|
|
46558
|
-
|
|
48015
|
+
const canRenderWithoutConfig = !!triggerType;
|
|
48016
|
+
if (!config && !previewMode && !canRenderWithoutConfig) {
|
|
46559
48017
|
return null;
|
|
46560
48018
|
}
|
|
46561
48019
|
// Get button icon based on state
|
|
46562
48020
|
const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
|
|
46563
48021
|
// Embedded mode renders directly without wrapper positioning
|
|
46564
48022
|
if (isEmbedded) {
|
|
46565
|
-
return (jsxRuntimeExports.jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsxRuntimeExports.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping,
|
|
46566
|
-
}
|
|
46567
|
-
|
|
48023
|
+
return (jsxRuntimeExports.jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsxRuntimeExports.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: sendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
|
|
48024
|
+
}
|
|
48025
|
+
// Determine trigger class for container
|
|
48026
|
+
const triggerClass = effectiveTriggerType === 'pill-text'
|
|
48027
|
+
? 'trigger-pill-text'
|
|
48028
|
+
: effectiveTriggerType === 'input-bar'
|
|
48029
|
+
? 'trigger-input-bar'
|
|
48030
|
+
: '';
|
|
48031
|
+
// Size class for CSS targeting (used by input-bar trigger for width matching)
|
|
48032
|
+
const sizeClass = `size-${effectiveSize}`;
|
|
48033
|
+
return (jsxRuntimeExports.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxRuntimeExports.jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''} ${containerMode ? 'container-mode' : ''} ${triggerClass} ${sizeClass}`, children: [isOpen && (jsxRuntimeExports.jsx(ChatWindow, { messages: demoMode && !isDemoComplete ? demoMessages : messages, isLoading: demoMode && !isDemoComplete ? false : isLoading, isTyping: demoMode && !isDemoComplete ? isDemoTyping : isTyping, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick, onActionDismiss: dismissAction,
|
|
46568
48034
|
// Chat history props (only active when persistConversation is true)
|
|
46569
48035
|
conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
|
|
46570
48036
|
// Override props for live preview
|
|
46571
|
-
headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsxRuntimeExports.jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsxRuntimeExports.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntimeExports.jsx(IconComponent, {}) }) })] }) }));
|
|
48037
|
+
headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), effectiveTriggerType === 'button' && !isOpen && effectiveWelcomeBubbleText && (previewMode || showWelcomeBubble) && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-welcome-bubble", onClick: handleToggle, children: [jsxRuntimeExports.jsx("span", { children: effectiveWelcomeBubbleText }), jsxRuntimeExports.jsx("button", { className: "ai-chat-welcome-bubble-close", onClick: handleDismissBubble, "aria-label": "Dismiss", children: jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsxRuntimeExports.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }) }), jsxRuntimeExports.jsx("div", { className: "ai-chat-welcome-bubble-arrow" })] })), effectiveTriggerType === 'button' && (jsxRuntimeExports.jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsxRuntimeExports.jsx("div", { className: "ai-chat-button-svg", children: jsxRuntimeExports.jsx(IconComponent, {}) }) })), effectiveTriggerType === 'pill-text' && (jsxRuntimeExports.jsxs("button", { className: `ai-chat-trigger-pill ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Close chat" : "Open chat", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-trigger-pill-icon", children: jsxRuntimeExports.jsx(IconComponent, {}) }), !isOpen && jsxRuntimeExports.jsx("span", { children: effectiveTriggerText })] })), effectiveTriggerType === 'input-bar' && !isOpen && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-trigger-input-container", children: [jsxRuntimeExports.jsx("button", { type: "button", className: "ai-chat-trigger-input-expand", onClick: handleToggle, "aria-label": "Open chat", children: jsxRuntimeExports.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("polyline", { points: "18 15 12 9 6 15" }) }) }), jsxRuntimeExports.jsxs("form", { className: "ai-chat-trigger-input-wrapper", onSubmit: handleInputBarSubmit, children: [jsxRuntimeExports.jsx("input", { type: "text", className: "ai-chat-trigger-input", placeholder: effectivePlaceholder || "Ask me anything...", value: isDemoAnimatingInput ? demoInputBarText : inputBarValue, onChange: (e) => !isDemoAnimatingInput && setInputBarValue(e.target.value), readOnly: isDemoAnimatingInput, "aria-label": "Chat input" }), jsxRuntimeExports.jsx("button", { type: "submit", className: "ai-chat-trigger-input-btn", disabled: isDemoAnimatingInput ? !demoInputBarText.trim() : !inputBarValue.trim(), "aria-label": "Send message", children: jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntimeExports.jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }), jsxRuntimeExports.jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })] }) })] })] }))] }) }));
|
|
46572
48038
|
};
|
|
46573
48039
|
|
|
46574
48040
|
/**
|