@chatwidgetai/chat-widget 0.3.0 → 0.3.1
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 +1176 -400
- package/dist/ai-chat-widget.umd.js.map +1 -1
- package/dist/api/client.d.ts +2 -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 +0 -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} +2 -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.esm.js +1176 -400
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1176 -400
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +8 -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
package/dist/index.esm.js
CHANGED
|
@@ -8,11 +8,14 @@ async function* parseSSEStream(response, validator) {
|
|
|
8
8
|
const reader = response.body.getReader();
|
|
9
9
|
const decoder = new TextDecoder();
|
|
10
10
|
let buffer = "";
|
|
11
|
+
let eventCount = 0;
|
|
11
12
|
try {
|
|
12
13
|
while (true) {
|
|
13
14
|
const { done, value } = await reader.read();
|
|
14
|
-
if (done)
|
|
15
|
+
if (done) {
|
|
16
|
+
console.log(`[SSE Parser] Stream ended normally after ${eventCount} events`);
|
|
15
17
|
break;
|
|
18
|
+
}
|
|
16
19
|
buffer += decoder.decode(value, { stream: true });
|
|
17
20
|
const chunks = buffer.split("\n\n");
|
|
18
21
|
buffer = chunks.pop() || "";
|
|
@@ -24,6 +27,7 @@ async function* parseSSEStream(response, validator) {
|
|
|
24
27
|
const data = JSON.parse(line.slice(6));
|
|
25
28
|
if (validator) {
|
|
26
29
|
if (validator(data)) {
|
|
30
|
+
eventCount++;
|
|
27
31
|
yield data;
|
|
28
32
|
}
|
|
29
33
|
else {
|
|
@@ -31,6 +35,7 @@ async function* parseSSEStream(response, validator) {
|
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
37
|
else {
|
|
38
|
+
eventCount++;
|
|
34
39
|
yield data;
|
|
35
40
|
}
|
|
36
41
|
}
|
|
@@ -43,6 +48,10 @@ async function* parseSSEStream(response, validator) {
|
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error(`[SSE Parser] Stream error after ${eventCount} events:`, error);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
46
55
|
finally {
|
|
47
56
|
reader.releaseLock();
|
|
48
57
|
}
|
|
@@ -176,7 +185,7 @@ class WidgetApiClient {
|
|
|
176
185
|
const result = await response.json();
|
|
177
186
|
return result.file;
|
|
178
187
|
}
|
|
179
|
-
async *sendAgentMessageStream(conversationId, message, fileIds) {
|
|
188
|
+
async *sendAgentMessageStream(conversationId, message, fileIds, signal) {
|
|
180
189
|
const headers = {
|
|
181
190
|
'Content-Type': 'application/json',
|
|
182
191
|
};
|
|
@@ -192,6 +201,7 @@ class WidgetApiClient {
|
|
|
192
201
|
fileIds,
|
|
193
202
|
timeZone: this.getTimeZone(),
|
|
194
203
|
}),
|
|
204
|
+
signal,
|
|
195
205
|
});
|
|
196
206
|
if (!response.ok) {
|
|
197
207
|
throw await buildApiError(response, 'Failed to send agent message');
|
|
@@ -200,7 +210,7 @@ class WidgetApiClient {
|
|
|
200
210
|
return typeof data === 'object' && data !== null && 'type' in data;
|
|
201
211
|
});
|
|
202
212
|
}
|
|
203
|
-
async *continueAgentMessageStream(conversationId, toolCallId, state) {
|
|
213
|
+
async *continueAgentMessageStream(conversationId, toolCallId, state, signal) {
|
|
204
214
|
const headers = {
|
|
205
215
|
'Content-Type': 'application/json',
|
|
206
216
|
};
|
|
@@ -216,6 +226,7 @@ class WidgetApiClient {
|
|
|
216
226
|
state,
|
|
217
227
|
timeZone: this.getTimeZone(),
|
|
218
228
|
}),
|
|
229
|
+
signal,
|
|
219
230
|
});
|
|
220
231
|
if (!response.ok) {
|
|
221
232
|
throw await buildApiError(response, 'Failed to continue agent');
|
|
@@ -27120,18 +27131,14 @@ const formatToolName = (name) => {
|
|
|
27120
27131
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
27121
27132
|
.join(' ');
|
|
27122
27133
|
};
|
|
27123
|
-
const GearIcon = ({ spinning = false }) => (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: [jsx("path", { d: "M12 20a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" }), jsx("path", { d: "M12 14a2 2 0 1 0 0-4 2 2 0 0 0 0 4Z" }), jsx("path", { d: "M12 2v2" }), jsx("path", { d: "M12 22v-2" }), jsx("path", { d: "m17 20.66-1-1.73" }), jsx("path", { d: "M11 10.27 7 3.34" }), jsx("path", { d: "m20.66 17-1.73-1" }), jsx("path", { d: "m3.34 7 1.73 1" }), jsx("path", { d: "M14 12h8" }), jsx("path", { d: "M2 12h2" }), jsx("path", { d: "m20.66 7-1.73 1" }), jsx("path", { d: "m3.34 17 1.73-1" }), jsx("path", { d: "m17 3.34-1 1.73" }), jsx("path", { d: "m11 13.73-4 6.93" })] }));
|
|
27124
|
-
const CheckIcon$2 = () => (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: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
27125
|
-
const ErrorIcon = () => (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: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }));
|
|
27126
27134
|
function ToolIndicator({ badges, className = '' }) {
|
|
27127
|
-
|
|
27128
|
-
return (jsxs("div", { className: `ai-chat-tool-row ${className}`, children: [jsx(GearIcon, { spinning: isAnyLoading }), jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsxs("div", { className: `ai-chat-tool-badge ${badge.status}`, children: [badge.status !== 'loading' && (badge.status === 'error' ? jsx(ErrorIcon, {}) : jsx(CheckIcon$2, {})), jsx("span", { className: "tool-name", children: formatToolName(badge.name) })] }, badge.id))) })] }));
|
|
27135
|
+
return (jsx("div", { className: `ai-chat-tool-row ${className}`, children: jsx("div", { className: "ai-chat-tool-badges", children: badges.map((badge) => (jsx("div", { className: `ai-chat-tool-badge ${badge.status}`, children: jsx("span", { className: "tool-name", children: formatToolName(badge.name) }) }, badge.id))) }) }));
|
|
27129
27136
|
}
|
|
27130
27137
|
|
|
27131
27138
|
// SVG Icon components
|
|
27132
27139
|
const ThumbsUpIcon = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: 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" }) }));
|
|
27133
27140
|
const ThumbsDownIcon = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: 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" }) }));
|
|
27134
|
-
const CheckIcon$
|
|
27141
|
+
const CheckIcon$2 = () => (jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
27135
27142
|
const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
|
|
27136
27143
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
27137
27144
|
const [submitted, setSubmitted] = useState(false);
|
|
@@ -27152,10 +27159,10 @@ const FeedbackButtons = ({ messageId, currentFeedback, onFeedback, }) => {
|
|
|
27152
27159
|
setIsSubmitting(false);
|
|
27153
27160
|
}
|
|
27154
27161
|
};
|
|
27155
|
-
return (jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsx(ThumbsUpIcon, {}) }), 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: jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsx("span", { className: "ai-chat-feedback-checkmark", children: jsx(CheckIcon$
|
|
27162
|
+
return (jsxs("div", { className: `ai-chat-feedback ${submitted ? 'submitted' : ''}`, children: [jsxs("div", { className: "ai-chat-feedback-buttons", children: [jsx("button", { className: `ai-chat-feedback-button ${currentFeedback === 'positive' ? 'active' : ''}`, onClick: () => handleFeedback('positive'), disabled: isDisabled, "aria-label": "Helpful", title: "This was helpful", children: jsx(ThumbsUpIcon, {}) }), 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: jsx(ThumbsDownIcon, {}) })] }), submitted && (jsxs("div", { className: "ai-chat-feedback-message", "aria-live": "polite", children: [jsx("span", { className: "ai-chat-feedback-checkmark", children: jsx(CheckIcon$2, {}) }), jsx("span", { className: "ai-chat-feedback-text", children: "Thanks for feedback" })] }))] }));
|
|
27156
27163
|
};
|
|
27157
27164
|
|
|
27158
|
-
const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback,
|
|
27165
|
+
const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
|
|
27159
27166
|
const formatTime = (timestamp) => {
|
|
27160
27167
|
const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
|
|
27161
27168
|
return date.toLocaleTimeString('en-US', {
|
|
@@ -27175,15 +27182,15 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
|
|
|
27175
27182
|
return null;
|
|
27176
27183
|
}
|
|
27177
27184
|
// AI message rendering
|
|
27185
|
+
// Note: Actions are rendered by ToolMessageGroup for tool messages, not here
|
|
27178
27186
|
if (isAssistant) {
|
|
27179
27187
|
const aiContent = message.message.content || '';
|
|
27180
27188
|
const hasContent = aiContent.trim().length > 0;
|
|
27181
27189
|
if (!hasContent)
|
|
27182
27190
|
return null;
|
|
27183
|
-
|
|
27184
|
-
|
|
27185
|
-
|
|
27186
|
-
return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxs("div", { className: "ai-chat-error-indicator", children: [jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "error-text", children: "Error" })] })), jsx(Markdown, { remarkPlugins: [remarkGfm], children: aiContent })] }), actionRenderer && message.action && actionRenderer(message, accentColor), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
|
|
27191
|
+
return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsx("div", { className: "ai-chat-message-content", children: jsx(Markdown, { remarkPlugins: [remarkGfm], components: {
|
|
27192
|
+
table: ({ children, ...props }) => (jsx("div", { className: "table-wrapper", children: jsx("div", { className: "table-scroll", children: jsx("table", { ...props, children: children }) }) })),
|
|
27193
|
+
}, children: aiContent }) }), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] }))] }));
|
|
27187
27194
|
}
|
|
27188
27195
|
// System message rendering
|
|
27189
27196
|
if (isSystem) {
|
|
@@ -27197,35 +27204,85 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedb
|
|
|
27197
27204
|
return null;
|
|
27198
27205
|
};
|
|
27199
27206
|
|
|
27200
|
-
|
|
27207
|
+
// Centralized action state logic
|
|
27208
|
+
function isActionComplete(state) {
|
|
27209
|
+
if (!state)
|
|
27210
|
+
return false;
|
|
27211
|
+
const TERMINAL_STATUSES = [
|
|
27212
|
+
'completed', 'booked', 'scheduled', 'cancelled', 'failed', 'error',
|
|
27213
|
+
'displaying', 'clicked', 'contacted', 'submitted', 'sent'
|
|
27214
|
+
];
|
|
27215
|
+
const status = state.status;
|
|
27216
|
+
if (typeof status === 'string' && TERMINAL_STATUSES.includes(status)) {
|
|
27217
|
+
return true;
|
|
27218
|
+
}
|
|
27219
|
+
// For non-halting actions (query_contact_directory, etc.) with results/success
|
|
27220
|
+
if (!status && (state.success !== undefined || state.results !== undefined)) {
|
|
27221
|
+
return true;
|
|
27222
|
+
}
|
|
27223
|
+
return false;
|
|
27224
|
+
}
|
|
27225
|
+
function isActionLoading(message) {
|
|
27226
|
+
if (!message.action)
|
|
27227
|
+
return false;
|
|
27228
|
+
if (message.action.done)
|
|
27229
|
+
return false;
|
|
27230
|
+
if (message.isStreaming)
|
|
27231
|
+
return true;
|
|
27232
|
+
const state = message.action.state;
|
|
27233
|
+
return !isActionComplete(state);
|
|
27234
|
+
}
|
|
27235
|
+
const ToolMessageGroup = ({ messages, getActionRenderer, showToolIndicator = true, accentColor, variant }) => {
|
|
27201
27236
|
const actionMessages = messages.filter(message => message.action);
|
|
27237
|
+
// Debug logging
|
|
27238
|
+
console.log('[DEBUG ToolMessageGroup] ========================================');
|
|
27239
|
+
console.log('[DEBUG ToolMessageGroup] Total messages:', messages.length);
|
|
27240
|
+
console.log('[DEBUG ToolMessageGroup] Messages with action:', actionMessages.length);
|
|
27241
|
+
console.log('[DEBUG ToolMessageGroup] hasGetActionRenderer:', !!getActionRenderer);
|
|
27242
|
+
messages.forEach((msg, i) => {
|
|
27243
|
+
console.log(`[DEBUG ToolMessageGroup] Message ${i}:`, {
|
|
27244
|
+
id: msg.id,
|
|
27245
|
+
role: msg.message.role,
|
|
27246
|
+
hasAction: !!msg.action,
|
|
27247
|
+
actionImpl: msg.action?.implementation,
|
|
27248
|
+
toolExecuting: msg.toolExecuting,
|
|
27249
|
+
});
|
|
27250
|
+
});
|
|
27251
|
+
actionMessages.forEach((msg, i) => {
|
|
27252
|
+
const impl = msg.action?.implementation || '';
|
|
27253
|
+
const renderer = getActionRenderer?.(impl);
|
|
27254
|
+
console.log(`[DEBUG ToolMessageGroup] Action ${i}:`, {
|
|
27255
|
+
implementation: impl,
|
|
27256
|
+
hasRenderer: !!renderer,
|
|
27257
|
+
rendererType: renderer ? typeof renderer : 'undefined',
|
|
27258
|
+
state: msg.action?.state,
|
|
27259
|
+
});
|
|
27260
|
+
});
|
|
27202
27261
|
// If tool indicator is hidden AND there are no action cards to render, don't render anything
|
|
27203
|
-
// This prevents empty wrapper divs that cause layout jumping
|
|
27204
27262
|
if (!showToolIndicator && actionMessages.length === 0) {
|
|
27205
27263
|
return null;
|
|
27206
27264
|
}
|
|
27207
27265
|
const badges = messages.map((message) => {
|
|
27208
27266
|
const toolName = message.toolExecuting || message.message.name || 'Tool';
|
|
27209
27267
|
const hasError = message.isError || false;
|
|
27210
|
-
const
|
|
27211
|
-
const actionStatus = actionState?.status;
|
|
27212
|
-
const terminalStatuses = ['completed', 'booked', 'scheduled', 'failed', 'cancelled', 'displaying', 'clicked'];
|
|
27213
|
-
const isTerminalStatus = actionStatus && terminalStatuses.includes(actionStatus);
|
|
27214
|
-
const isDone = message.action ? (message.action.done ?? isTerminalStatus ?? false) : !message.isStreaming;
|
|
27215
|
-
const isLoading = !isDone;
|
|
27268
|
+
const loading = isActionLoading(message);
|
|
27216
27269
|
return {
|
|
27217
27270
|
id: message.id,
|
|
27218
27271
|
name: toolName,
|
|
27219
|
-
status:
|
|
27272
|
+
status: loading ? 'loading' : hasError ? 'error' : 'completed',
|
|
27220
27273
|
};
|
|
27221
27274
|
});
|
|
27222
27275
|
return (jsxs("div", { className: "ai-chat-message tool", children: [showToolIndicator && jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
|
|
27223
|
-
if (!message.action || !getActionRenderer)
|
|
27276
|
+
if (!message.action || !getActionRenderer) {
|
|
27277
|
+
console.log('[ToolMessageGroup] Skipping - no action or renderer:', { hasAction: !!message.action, hasGetRenderer: !!getActionRenderer });
|
|
27224
27278
|
return null;
|
|
27279
|
+
}
|
|
27225
27280
|
const renderer = getActionRenderer(message.action.implementation);
|
|
27226
|
-
if (!renderer)
|
|
27281
|
+
if (!renderer) {
|
|
27282
|
+
console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
|
|
27227
27283
|
return null;
|
|
27228
|
-
|
|
27284
|
+
}
|
|
27285
|
+
return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant) }, `action-${message.id}`));
|
|
27229
27286
|
})] }));
|
|
27230
27287
|
};
|
|
27231
27288
|
|
|
@@ -27287,12 +27344,16 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
|
|
|
27287
27344
|
};
|
|
27288
27345
|
|
|
27289
27346
|
const MessageList = (props) => {
|
|
27290
|
-
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, } = props;
|
|
27347
|
+
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, variant, } = props;
|
|
27291
27348
|
const containerRef = useRef(null);
|
|
27292
27349
|
const messagesEndRef = useRef(null);
|
|
27293
27350
|
const [showScrollButton, setShowScrollButton] = useState(false);
|
|
27294
27351
|
const prevMessageCountRef = useRef(0);
|
|
27295
|
-
const hasActiveAction = useMemo(() =>
|
|
27352
|
+
const hasActiveAction = useMemo(() => {
|
|
27353
|
+
// Find the last tool message and check if its action is still active (not done)
|
|
27354
|
+
const lastToolMsg = [...messages].reverse().find(msg => msg.message.role === 'tool');
|
|
27355
|
+
return lastToolMsg?.action && lastToolMsg.action.done !== true;
|
|
27356
|
+
}, [messages]);
|
|
27296
27357
|
const checkScrollPosition = useCallback(() => {
|
|
27297
27358
|
const c = containerRef.current;
|
|
27298
27359
|
if (!c)
|
|
@@ -27328,15 +27389,31 @@ const MessageList = (props) => {
|
|
|
27328
27389
|
checkScrollPosition();
|
|
27329
27390
|
}, [messages, isTyping, checkScrollPosition]);
|
|
27330
27391
|
const groupedMessages = useMemo(() => {
|
|
27392
|
+
console.log('[DEBUG MessageList] ========================================');
|
|
27393
|
+
console.log('[DEBUG MessageList] Processing messages:', messages.length);
|
|
27394
|
+
messages.forEach((m, i) => {
|
|
27395
|
+
console.log(`[DEBUG MessageList] Message ${i}:`, {
|
|
27396
|
+
id: m.id,
|
|
27397
|
+
role: m.message.role,
|
|
27398
|
+
hasAction: !!m.action,
|
|
27399
|
+
actionImpl: m.action?.implementation,
|
|
27400
|
+
content: (m.message.content || '').substring(0, 50),
|
|
27401
|
+
});
|
|
27402
|
+
});
|
|
27331
27403
|
const result = [];
|
|
27332
27404
|
let toolGroup = [];
|
|
27333
|
-
const flush = () => {
|
|
27334
|
-
|
|
27335
|
-
|
|
27336
|
-
|
|
27405
|
+
const flush = () => {
|
|
27406
|
+
if (toolGroup.length) {
|
|
27407
|
+
console.log('[DEBUG MessageList] Flushing tool group with', toolGroup.length, 'messages');
|
|
27408
|
+
result.push({ type: 'tool-group', messages: [...toolGroup] });
|
|
27409
|
+
toolGroup = [];
|
|
27410
|
+
}
|
|
27411
|
+
};
|
|
27337
27412
|
for (const m of messages) {
|
|
27338
|
-
if (m.message.role === 'tool')
|
|
27413
|
+
if (m.message.role === 'tool') {
|
|
27414
|
+
console.log('[DEBUG MessageList] Adding to tool group:', m.id);
|
|
27339
27415
|
toolGroup.push(m);
|
|
27416
|
+
}
|
|
27340
27417
|
else if (m.message.role === 'user') {
|
|
27341
27418
|
flush();
|
|
27342
27419
|
result.push({ type: 'message', message: m });
|
|
@@ -27348,6 +27425,7 @@ const MessageList = (props) => {
|
|
|
27348
27425
|
flush();
|
|
27349
27426
|
result.push({ type: 'message', message: m });
|
|
27350
27427
|
}
|
|
27428
|
+
// Don't flush on empty assistant messages - let tools continue grouping
|
|
27351
27429
|
}
|
|
27352
27430
|
else {
|
|
27353
27431
|
flush();
|
|
@@ -27355,13 +27433,22 @@ const MessageList = (props) => {
|
|
|
27355
27433
|
}
|
|
27356
27434
|
}
|
|
27357
27435
|
flush();
|
|
27436
|
+
console.log('[DEBUG MessageList] Final grouped result:', result.length, 'items');
|
|
27437
|
+
result.forEach((item, i) => {
|
|
27438
|
+
if (item.type === 'tool-group') {
|
|
27439
|
+
console.log(`[DEBUG MessageList] Group ${i}: tool-group with ${item.messages.length} messages`);
|
|
27440
|
+
}
|
|
27441
|
+
else {
|
|
27442
|
+
console.log(`[DEBUG MessageList] Group ${i}: message (${item.message.message.role})`);
|
|
27443
|
+
}
|
|
27444
|
+
});
|
|
27358
27445
|
return result;
|
|
27359
27446
|
}, [messages]);
|
|
27360
27447
|
const hasSuggestions = messages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
|
|
27361
27448
|
const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
|
|
27362
27449
|
return (jsxs("div", { ref: containerRef, className: "ai-chat-messages", role: "log", "aria-live": "polite", children: [showWelcome && (jsxs("div", { className: "ai-chat-welcome", children: [welcomeTitle && jsx("div", { className: "ai-chat-welcome-title", children: welcomeTitle }), welcomeMessage && jsx("div", { className: "ai-chat-welcome-text", children: welcomeMessage }), hasSuggestions && jsx(SuggestedQuestions, { questions: suggestedQuestions, onQuestionClick: onSuggestedQuestionClick })] })), groupedMessages.map((item, i) => {
|
|
27363
27450
|
if (item.type === 'tool-group') {
|
|
27364
|
-
return jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor }, `tg-${i}`);
|
|
27451
|
+
return jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant }, `tg-${i}`);
|
|
27365
27452
|
}
|
|
27366
27453
|
const isLast = i === groupedMessages.length - 1;
|
|
27367
27454
|
const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
|
|
@@ -27380,7 +27467,7 @@ const formatFileSize = (bytes) => {
|
|
|
27380
27467
|
return (bytes / 1024).toFixed(1) + ' KB';
|
|
27381
27468
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
27382
27469
|
};
|
|
27383
|
-
const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, }) => {
|
|
27470
|
+
const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled = false, enableFileUpload = false, separateFromChat = true, showDataPolicy = true, onDataPolicyClick, }) => {
|
|
27384
27471
|
const [value, setValue] = useState('');
|
|
27385
27472
|
const [selectedFiles, setSelectedFiles] = useState([]);
|
|
27386
27473
|
const textareaRef = useRef(null);
|
|
@@ -27415,10 +27502,10 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
|
|
|
27415
27502
|
}
|
|
27416
27503
|
};
|
|
27417
27504
|
const canSend = value.trim() || selectedFiles.length > 0;
|
|
27418
|
-
return (jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxs("div", { className: "ai-chat-file-item", children: [jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxs("div", { className: "ai-chat-file-info", children: [jsx("span", { className: "ai-chat-file-name", children: file.name }), jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxs(Fragment, { children: [jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: 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" }) }) })] })), 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" }), jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsx("path", { d: "M12 19V5" }), jsx("path", { d: "M5 12l7-7 7 7" })] }) })] })] }));
|
|
27505
|
+
return (jsxs("div", { className: `ai-chat-input-container ${separateFromChat ? 'separate' : 'integrated'}`, children: [selectedFiles.length > 0 && (jsx("div", { className: "ai-chat-file-list", children: selectedFiles.map((file, index) => (jsxs("div", { className: "ai-chat-file-item", children: [jsx("span", { className: "ai-chat-file-extension", children: getFileExtension(file.name) }), jsxs("div", { className: "ai-chat-file-info", children: [jsx("span", { className: "ai-chat-file-name", children: file.name }), jsx("span", { className: "ai-chat-file-size", children: formatFileSize(file.size) })] }), jsx("button", { className: "ai-chat-file-remove", onClick: () => handleRemoveFile(index), "aria-label": "Remove file", children: jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) })] }, index))) })), jsxs("div", { className: "ai-chat-input-wrapper", children: [enableFileUpload && (jsxs(Fragment, { children: [jsx("input", { ref: fileInputRef, type: "file", onChange: handleFileSelect, style: { display: 'none' }, multiple: true, accept: ALLOWED_EXTENSIONS.join(',') }), jsx("button", { className: "ai-chat-file-button", onClick: () => fileInputRef.current?.click(), disabled: disabled, "aria-label": "Attach file", children: jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: 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" }) }) })] })), 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" }), jsx("button", { className: `ai-chat-send-button ${canSend ? 'active' : ''}`, onClick: handleSend, disabled: disabled || !canSend, "aria-label": "Send message", children: jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", children: [jsx("path", { d: "M12 19V5" }), jsx("path", { d: "M5 12l7-7 7 7" })] }) })] }), showDataPolicy && (jsxs("div", { className: "ai-chat-data-policy", children: [jsx("span", { children: "KI-generierte Antworten k\u00F6nnen unzutreffend sein." }), onDataPolicyClick && (jsxs(Fragment, { children: [' ', jsx("button", { type: "button", className: "ai-chat-data-policy-link", onClick: onDataPolicyClick, children: "Datenschutzhinweis" })] }))] }))] }));
|
|
27419
27506
|
};
|
|
27420
27507
|
|
|
27421
|
-
function groupSlotsByDate(slots) {
|
|
27508
|
+
function groupSlotsByDate$1(slots) {
|
|
27422
27509
|
const grouped = new Map();
|
|
27423
27510
|
for (const slot of slots) {
|
|
27424
27511
|
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
@@ -27432,7 +27519,7 @@ function groupSlotsByDate(slots) {
|
|
|
27432
27519
|
}
|
|
27433
27520
|
return grouped;
|
|
27434
27521
|
}
|
|
27435
|
-
function formatDate(dateStr) {
|
|
27522
|
+
function formatDate$1(dateStr) {
|
|
27436
27523
|
try {
|
|
27437
27524
|
const date = new Date(dateStr);
|
|
27438
27525
|
return new Intl.DateTimeFormat("en-US", {
|
|
@@ -27445,16 +27532,16 @@ function formatDate(dateStr) {
|
|
|
27445
27532
|
return dateStr;
|
|
27446
27533
|
}
|
|
27447
27534
|
}
|
|
27448
|
-
function CalendarIcon() {
|
|
27535
|
+
function CalendarIcon$1() {
|
|
27449
27536
|
return (jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: 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" }) }));
|
|
27450
27537
|
}
|
|
27451
|
-
function CheckIcon() {
|
|
27538
|
+
function CheckIcon$1() {
|
|
27452
27539
|
return (jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: 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" }) }));
|
|
27453
27540
|
}
|
|
27454
|
-
function ExternalLinkIcon$
|
|
27541
|
+
function ExternalLinkIcon$2() {
|
|
27455
27542
|
return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
27456
27543
|
}
|
|
27457
|
-
function Skeleton({ width, height, borderRadius = '4px' }) {
|
|
27544
|
+
function Skeleton$1({ width, height, borderRadius = '4px' }) {
|
|
27458
27545
|
return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
27459
27546
|
}
|
|
27460
27547
|
function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
|
|
@@ -27471,13 +27558,12 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
|
|
|
27471
27558
|
: [];
|
|
27472
27559
|
const allowTopic = state.allowTopic !== false;
|
|
27473
27560
|
const isBooked = state.status === "booked";
|
|
27474
|
-
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
27561
|
+
const slotsByDate = groupSlotsByDate$1(availableSlots);
|
|
27475
27562
|
const dates = Array.from(slotsByDate.keys()).sort();
|
|
27476
27563
|
const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
|
|
27477
27564
|
const [selectedSlot, setSelectedSlot] = useState(null);
|
|
27478
27565
|
const [topic, setTopic] = useState("");
|
|
27479
27566
|
const [error, setError] = useState(null);
|
|
27480
|
-
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
27481
27567
|
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
27482
27568
|
const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
|
|
27483
27569
|
const onConfirm = () => {
|
|
@@ -27490,8 +27576,245 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
|
|
|
27490
27576
|
return;
|
|
27491
27577
|
}
|
|
27492
27578
|
setError(null);
|
|
27579
|
+
onComplete?.(action.toolCallId, {
|
|
27580
|
+
...action.state,
|
|
27581
|
+
selectedSlot: {
|
|
27582
|
+
startTime: selectedSlot.startTime,
|
|
27583
|
+
endTime: selectedSlot.endTime,
|
|
27584
|
+
},
|
|
27585
|
+
topic: allowTopic ? topic.trim() : null,
|
|
27586
|
+
});
|
|
27587
|
+
};
|
|
27588
|
+
// Booked state
|
|
27589
|
+
if (isBooked) {
|
|
27590
|
+
const bookedSlot = state.selectedSlot;
|
|
27591
|
+
const bookedTopic = state.topic;
|
|
27592
|
+
const eventLink = state.bookedEventLink;
|
|
27593
|
+
return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon$1, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Google Calendar", jsx(ExternalLinkIcon$2, {})] }))] })] }));
|
|
27594
|
+
}
|
|
27595
|
+
// Skeleton loading state - show when waiting for backend after user confirms
|
|
27596
|
+
const isWaitingForBackend = !action.done && state.selectedSlot && !isBooked;
|
|
27597
|
+
if (isWaitingForBackend) {
|
|
27598
|
+
return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton$1, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton$1, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton$1, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton$1, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton$1, { width: "50px", height: "12px", borderRadius: "4px" }), jsx(Skeleton$1, { width: "200px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton$1, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
27599
|
+
}
|
|
27600
|
+
// Booking form
|
|
27601
|
+
return (jsxs("div", { className: `ai-chat-action-card ai-chat-google-calendar ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon$1, {}), "Schedule an Appointment"] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), 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) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
|
|
27602
|
+
setSelectedDate(date);
|
|
27603
|
+
setSelectedSlot(null);
|
|
27604
|
+
}, children: formatDate$1(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (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 && jsx("div", { className: "ai-chat-action-error", children: error }), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
|
|
27605
|
+
}
|
|
27606
|
+
|
|
27607
|
+
function groupSlotsByDate(slots) {
|
|
27608
|
+
const grouped = new Map();
|
|
27609
|
+
for (const slot of slots) {
|
|
27610
|
+
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
27611
|
+
continue;
|
|
27612
|
+
}
|
|
27613
|
+
const date = slot.startTime.slice(0, 10);
|
|
27614
|
+
if (!grouped.has(date)) {
|
|
27615
|
+
grouped.set(date, []);
|
|
27616
|
+
}
|
|
27617
|
+
grouped.get(date).push(slot);
|
|
27618
|
+
}
|
|
27619
|
+
return grouped;
|
|
27620
|
+
}
|
|
27621
|
+
function formatDate(dateStr) {
|
|
27622
|
+
try {
|
|
27623
|
+
const date = new Date(dateStr);
|
|
27624
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
27625
|
+
weekday: "short",
|
|
27626
|
+
month: "short",
|
|
27627
|
+
day: "numeric",
|
|
27628
|
+
}).format(date);
|
|
27629
|
+
}
|
|
27630
|
+
catch {
|
|
27631
|
+
return dateStr;
|
|
27632
|
+
}
|
|
27633
|
+
}
|
|
27634
|
+
function CalendarIcon() {
|
|
27635
|
+
return (jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: 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" }) }));
|
|
27636
|
+
}
|
|
27637
|
+
function MailIcon() {
|
|
27638
|
+
return (jsxs("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: [jsx("path", { d: "M2.003 5.884L10 9.882l7.997-3.998A2 2 0 0016 4H4a2 2 0 00-1.997 1.884z" }), jsx("path", { d: "M18 8.118l-8 4-8-4V14a2 2 0 002 2h12a2 2 0 002-2V8.118z" })] }));
|
|
27639
|
+
}
|
|
27640
|
+
function CheckIcon() {
|
|
27641
|
+
return (jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: 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" }) }));
|
|
27642
|
+
}
|
|
27643
|
+
function ErrorIcon() {
|
|
27644
|
+
return (jsx("svg", { className: "ai-chat-action-icon-error", viewBox: "0 0 20 20", fill: "currentColor", children: 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" }) }));
|
|
27645
|
+
}
|
|
27646
|
+
function ExternalLinkIcon$1() {
|
|
27647
|
+
return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
27648
|
+
}
|
|
27649
|
+
function Skeleton({ width, height, borderRadius = '4px' }) {
|
|
27650
|
+
return (jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
27651
|
+
}
|
|
27652
|
+
function PinInputGroup({ values, onChange, disabled }) {
|
|
27653
|
+
const inputRefs = useRef([]);
|
|
27654
|
+
const handleChange = (index, value) => {
|
|
27655
|
+
// Only allow digits
|
|
27656
|
+
const digit = value.replace(/[^0-9]/g, '');
|
|
27657
|
+
const newValues = [...values];
|
|
27658
|
+
newValues[index] = digit.slice(-1);
|
|
27659
|
+
onChange(newValues);
|
|
27660
|
+
// Auto-focus next input
|
|
27661
|
+
if (digit && index < 5) {
|
|
27662
|
+
inputRefs.current[index + 1]?.focus();
|
|
27663
|
+
}
|
|
27664
|
+
};
|
|
27665
|
+
const handleKeyDown = (index, e) => {
|
|
27666
|
+
if (e.key === 'Backspace' && !values[index] && index > 0) {
|
|
27667
|
+
inputRefs.current[index - 1]?.focus();
|
|
27668
|
+
}
|
|
27669
|
+
};
|
|
27670
|
+
const handlePaste = (e) => {
|
|
27671
|
+
e.preventDefault();
|
|
27672
|
+
const pastedData = e.clipboardData.getData('text').replace(/[^0-9]/g, '').slice(0, 6);
|
|
27673
|
+
const newValues = pastedData.split('').concat(Array(6 - pastedData.length).fill(''));
|
|
27674
|
+
onChange(newValues);
|
|
27675
|
+
// Focus the next empty input or the last one
|
|
27676
|
+
const nextIndex = Math.min(pastedData.length, 5);
|
|
27677
|
+
inputRefs.current[nextIndex]?.focus();
|
|
27678
|
+
};
|
|
27679
|
+
return (jsx("div", { className: "ai-chat-pin-input-group", children: values.map((value, index) => (jsx("input", { ref: (el) => {
|
|
27680
|
+
inputRefs.current[index] = el;
|
|
27681
|
+
}, 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))) }));
|
|
27682
|
+
}
|
|
27683
|
+
function MicrosoftCalendarCard({ action, onComplete, accentColor, className = '' }) {
|
|
27684
|
+
const state = action.state;
|
|
27685
|
+
const phase = state.phase || "awaiting_email";
|
|
27686
|
+
const allowTopic = state.allowTopic !== false;
|
|
27687
|
+
const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
|
|
27688
|
+
// Debug: Log state changes
|
|
27689
|
+
const prevStateRef = useRef(null);
|
|
27690
|
+
useEffect(() => {
|
|
27691
|
+
if (JSON.stringify(prevStateRef.current) !== JSON.stringify(state)) {
|
|
27692
|
+
console.log('[MicrosoftCalendarCard] State updated:', {
|
|
27693
|
+
phase: state.phase,
|
|
27694
|
+
hasError: !!state.errorMessage,
|
|
27695
|
+
error: state.errorMessage,
|
|
27696
|
+
slotsCount: state.availableSlots?.length || 0
|
|
27697
|
+
});
|
|
27698
|
+
prevStateRef.current = state;
|
|
27699
|
+
}
|
|
27700
|
+
}, [state]);
|
|
27701
|
+
// Email phase state
|
|
27702
|
+
const [email, setEmail] = useState("");
|
|
27703
|
+
const [emailError, setEmailError] = useState(null);
|
|
27704
|
+
// OTP phase state
|
|
27705
|
+
const [otpValues, setOtpValues] = useState(Array(6).fill(''));
|
|
27706
|
+
const [otpError, setOtpError] = useState(null);
|
|
27707
|
+
// Loading states
|
|
27708
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
27709
|
+
// Reset loading state when phase changes (backend has responded)
|
|
27710
|
+
// Use useEffect for reliable re-rendering
|
|
27711
|
+
useEffect(() => {
|
|
27712
|
+
console.log('[MicrosoftCalendarCard] Phase changed to:', phase);
|
|
27713
|
+
setIsSubmitting(false);
|
|
27714
|
+
// Clear errors when transitioning to new phase
|
|
27715
|
+
if (phase === "awaiting_email") {
|
|
27716
|
+
setEmailError(null);
|
|
27717
|
+
setOtpError(null);
|
|
27718
|
+
setSelectionError(null);
|
|
27719
|
+
}
|
|
27720
|
+
else if (phase === "awaiting_otp") {
|
|
27721
|
+
setOtpError(state.errorMessage || null);
|
|
27722
|
+
setEmailError(null);
|
|
27723
|
+
setSelectionError(null);
|
|
27724
|
+
// Clear OTP input for fresh attempt
|
|
27725
|
+
setOtpValues(Array(6).fill(''));
|
|
27726
|
+
}
|
|
27727
|
+
else if (phase === "awaiting_options") {
|
|
27728
|
+
setEmailError(null);
|
|
27729
|
+
setOtpError(null);
|
|
27730
|
+
setSelectionError(null);
|
|
27731
|
+
}
|
|
27732
|
+
else if (phase === "awaiting_booking") {
|
|
27733
|
+
setSelectionError(state.errorMessage || null);
|
|
27734
|
+
setEmailError(null);
|
|
27735
|
+
setOtpError(null);
|
|
27736
|
+
}
|
|
27737
|
+
else if (phase === "booked" || phase === "cancelled" || phase === "error") {
|
|
27738
|
+
setEmailError(null);
|
|
27739
|
+
setOtpError(null);
|
|
27740
|
+
setSelectionError(null);
|
|
27741
|
+
setSelectedId(null); // Reset selection
|
|
27742
|
+
}
|
|
27743
|
+
}, [phase, state.errorMessage]);
|
|
27744
|
+
// Selection phase state
|
|
27745
|
+
const rawSlots = state.availableSlots;
|
|
27746
|
+
const availableSlots = Array.isArray(rawSlots)
|
|
27747
|
+
? rawSlots.filter((slot) => slot !== null &&
|
|
27748
|
+
slot !== undefined &&
|
|
27749
|
+
typeof slot === "object" &&
|
|
27750
|
+
"startTime" in slot &&
|
|
27751
|
+
"endTime" in slot &&
|
|
27752
|
+
typeof slot.startTime === "string" &&
|
|
27753
|
+
typeof slot.endTime === "string")
|
|
27754
|
+
: [];
|
|
27755
|
+
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
27756
|
+
const dates = Array.from(slotsByDate.keys()).sort();
|
|
27757
|
+
const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
|
|
27758
|
+
const [selectedSlot, setSelectedSlot] = useState(null);
|
|
27759
|
+
const [topic, setTopic] = useState("");
|
|
27760
|
+
const [selectionError, setSelectionError] = useState(null);
|
|
27761
|
+
// Cancellation phase state
|
|
27762
|
+
const [selectedId, setSelectedId] = useState(null);
|
|
27763
|
+
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
27764
|
+
// Phase 1: Email Input
|
|
27765
|
+
const handleEmailSubmit = () => {
|
|
27766
|
+
const trimmedEmail = email.trim();
|
|
27767
|
+
if (!trimmedEmail) {
|
|
27768
|
+
setEmailError("Please enter your email address");
|
|
27769
|
+
return;
|
|
27770
|
+
}
|
|
27771
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(trimmedEmail)) {
|
|
27772
|
+
setEmailError("Please enter a valid email address");
|
|
27773
|
+
return;
|
|
27774
|
+
}
|
|
27775
|
+
setEmailError(null);
|
|
27776
|
+
setIsSubmitting(true);
|
|
27777
|
+
console.log('[MicrosoftCalendarCard] Submitting email:', trimmedEmail);
|
|
27778
|
+
setTimeout(() => {
|
|
27779
|
+
onComplete?.(action.toolCallId, {
|
|
27780
|
+
...action.state,
|
|
27781
|
+
email: trimmedEmail,
|
|
27782
|
+
});
|
|
27783
|
+
}, 50);
|
|
27784
|
+
};
|
|
27785
|
+
// Phase 2: OTP Verification
|
|
27786
|
+
const handleOtpSubmit = () => {
|
|
27787
|
+
const otpCode = otpValues.join('');
|
|
27788
|
+
if (otpCode.length !== 6) {
|
|
27789
|
+
setOtpError("Please enter the 6-digit code");
|
|
27790
|
+
return;
|
|
27791
|
+
}
|
|
27792
|
+
setOtpError(null);
|
|
27793
|
+
setIsSubmitting(true);
|
|
27794
|
+
console.log('[MicrosoftCalendarCard] Submitting OTP code');
|
|
27795
|
+
setTimeout(() => {
|
|
27796
|
+
onComplete?.(action.toolCallId, {
|
|
27797
|
+
...action.state,
|
|
27798
|
+
otpCode,
|
|
27799
|
+
});
|
|
27800
|
+
}, 50);
|
|
27801
|
+
};
|
|
27802
|
+
// Phase 3: Appointment Selection
|
|
27803
|
+
const handleAppointmentConfirm = () => {
|
|
27804
|
+
if (!selectedSlot) {
|
|
27805
|
+
setSelectionError("Please select a time slot");
|
|
27806
|
+
return;
|
|
27807
|
+
}
|
|
27808
|
+
if (allowTopic && !topic.trim()) {
|
|
27809
|
+
setSelectionError("Please enter a meeting topic");
|
|
27810
|
+
return;
|
|
27811
|
+
}
|
|
27812
|
+
setSelectionError(null);
|
|
27493
27813
|
setIsSubmitting(true);
|
|
27494
|
-
|
|
27814
|
+
console.log('[MicrosoftCalendarCard] Confirming appointment:', {
|
|
27815
|
+
slot: selectedSlot,
|
|
27816
|
+
topic: topic.trim()
|
|
27817
|
+
});
|
|
27495
27818
|
setTimeout(() => {
|
|
27496
27819
|
onComplete?.(action.toolCallId, {
|
|
27497
27820
|
...action.state,
|
|
@@ -27503,22 +27826,149 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
|
|
|
27503
27826
|
});
|
|
27504
27827
|
}, 50);
|
|
27505
27828
|
};
|
|
27506
|
-
//
|
|
27507
|
-
|
|
27829
|
+
// Handle "Use different email" button
|
|
27830
|
+
const handleUseDifferentEmail = () => {
|
|
27831
|
+
setEmail("");
|
|
27832
|
+
setEmailError(null);
|
|
27833
|
+
setOtpValues(Array(6).fill(''));
|
|
27834
|
+
setOtpError(null);
|
|
27835
|
+
onComplete?.(action.toolCallId, {
|
|
27836
|
+
phase: "awaiting_email",
|
|
27837
|
+
email: null,
|
|
27838
|
+
otpVerified: false,
|
|
27839
|
+
otpAttempts: 0,
|
|
27840
|
+
availableSlots: [],
|
|
27841
|
+
selectedSlot: null,
|
|
27842
|
+
topic: null,
|
|
27843
|
+
bookedEventId: null,
|
|
27844
|
+
bookedEventLink: null,
|
|
27845
|
+
allowTopic,
|
|
27846
|
+
errorMessage: null,
|
|
27847
|
+
});
|
|
27848
|
+
};
|
|
27849
|
+
// Phase 5: Booked Confirmation
|
|
27850
|
+
if (phase === "booked") {
|
|
27508
27851
|
const bookedSlot = state.selectedSlot;
|
|
27509
27852
|
const bookedTopic = state.topic;
|
|
27510
27853
|
const eventLink = state.bookedEventLink;
|
|
27511
|
-
|
|
27512
|
-
|
|
27513
|
-
|
|
27854
|
+
const bookedEmail = state.email;
|
|
27855
|
+
return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Confirmed"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TOPIC" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "TIME" }), jsx("span", { className: "ai-chat-action-value-large", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), bookedEmail && (jsxs("div", { className: "ai-chat-action-hint", children: ["A calendar invitation has been sent to ", bookedEmail] })), eventLink && (jsxs("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link-button", children: ["View in Outlook Calendar", jsx(ExternalLinkIcon$1, {})] }))] })] }));
|
|
27856
|
+
}
|
|
27857
|
+
// Phase 6: Cancelled Confirmation
|
|
27858
|
+
if (phase === "cancelled") {
|
|
27859
|
+
const cancelledSubject = state.cancelledEventSubject;
|
|
27860
|
+
const userEmail = state.email;
|
|
27861
|
+
return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-booked ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("div", { className: "ai-chat-action-success-icon-wrapper", children: jsx(CheckIcon, {}) }), "Appointment Cancelled"] }), jsxs("div", { className: "ai-chat-action-body", children: [cancelledSubject && (jsxs("div", { className: "ai-chat-action-detail-box", children: [jsx("span", { className: "ai-chat-action-label-small", children: "CANCELLED" }), jsx("span", { className: "ai-chat-action-value-large", children: cancelledSubject })] })), userEmail && (jsxs("div", { className: "ai-chat-action-hint", children: ["A cancellation notice has been sent to ", userEmail] }))] })] }));
|
|
27862
|
+
}
|
|
27863
|
+
// Error State
|
|
27864
|
+
if (phase === "error") {
|
|
27865
|
+
return (jsxs("div", { className: `ai-chat-action-card ai-chat-action-error ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(ErrorIcon, {}), "Error"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-error-message", children: state.errorMessage || "An error occurred. Please try again." }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
27866
|
+
setEmail("");
|
|
27867
|
+
setEmailError(null);
|
|
27868
|
+
setOtpValues(Array(6).fill(''));
|
|
27869
|
+
setOtpError(null);
|
|
27870
|
+
onComplete?.(action.toolCallId, {
|
|
27871
|
+
phase: "awaiting_email",
|
|
27872
|
+
email: null,
|
|
27873
|
+
otpVerified: false,
|
|
27874
|
+
otpAttempts: 0,
|
|
27875
|
+
availableSlots: [],
|
|
27876
|
+
selectedSlot: null,
|
|
27877
|
+
topic: null,
|
|
27878
|
+
bookedEventId: null,
|
|
27879
|
+
bookedEventLink: null,
|
|
27880
|
+
allowTopic,
|
|
27881
|
+
errorMessage: null,
|
|
27882
|
+
});
|
|
27883
|
+
}, children: "Start Over" })] })] }));
|
|
27884
|
+
}
|
|
27885
|
+
// Loading State
|
|
27514
27886
|
if (isSubmitting) {
|
|
27515
|
-
return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }),
|
|
27516
|
-
}
|
|
27517
|
-
//
|
|
27518
|
-
|
|
27519
|
-
|
|
27520
|
-
|
|
27521
|
-
|
|
27887
|
+
return (jsx("div", { className: `ai-chat-action-card ai-chat-action-skeleton ${className}`, style: accentStyle, children: jsxs("div", { className: "ai-chat-action-skeleton-content", children: [jsxs("div", { className: "ai-chat-action-skeleton-header", children: [jsx(Skeleton, { width: "28px", height: "28px", borderRadius: "50%" }), jsx(Skeleton, { width: "180px", height: "20px", borderRadius: "4px" })] }), jsxs("div", { className: "ai-chat-action-skeleton-box", children: [jsx(Skeleton, { width: "60px", height: "12px", borderRadius: "4px" }), jsx(Skeleton, { width: "120px", height: "18px", borderRadius: "4px" })] }), jsx(Skeleton, { width: "100%", height: "44px", borderRadius: "999px" })] }) }));
|
|
27888
|
+
}
|
|
27889
|
+
// Phase 1: Email Input
|
|
27890
|
+
if (phase === "awaiting_email") {
|
|
27891
|
+
const displayError = state.errorMessage || emailError;
|
|
27892
|
+
return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Schedule an Appointment"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-hint", children: "We'll send a verification code to your email" }), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `email-${action.toolCallId}`, className: "ai-chat-action-label", children: "Email Address" }), jsx("input", { id: `email-${action.toolCallId}`, type: "email", className: "ai-chat-action-input", placeholder: "your@email.com", value: email, onChange: (e) => {
|
|
27893
|
+
setEmail(e.target.value);
|
|
27894
|
+
setEmailError(null);
|
|
27895
|
+
}, onKeyPress: (e) => {
|
|
27896
|
+
if (e.key === 'Enter') {
|
|
27897
|
+
handleEmailSubmit();
|
|
27898
|
+
}
|
|
27899
|
+
}, autoFocus: true })] }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleEmailSubmit, children: "Continue" })] })] }));
|
|
27900
|
+
}
|
|
27901
|
+
// Phase 2: OTP Input
|
|
27902
|
+
if (phase === "awaiting_otp") {
|
|
27903
|
+
const displayError = state.errorMessage || otpError;
|
|
27904
|
+
const userEmail = state.email;
|
|
27905
|
+
return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(MailIcon, {}), "Verify Your Email"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsxs("div", { className: "ai-chat-action-hint", children: ["We sent a 6-digit code to ", jsx("strong", { children: userEmail })] }), jsx(PinInputGroup, { values: otpValues, onChange: (newValues) => {
|
|
27906
|
+
setOtpValues(newValues);
|
|
27907
|
+
setOtpError(null);
|
|
27908
|
+
// Auto-submit when all 6 digits are entered
|
|
27909
|
+
if (newValues.every(v => v.length === 1)) {
|
|
27910
|
+
console.log('[MicrosoftCalendarCard] Auto-submitting OTP (all 6 digits entered)');
|
|
27911
|
+
setIsSubmitting(true);
|
|
27912
|
+
const code = newValues.join('');
|
|
27913
|
+
setTimeout(() => {
|
|
27914
|
+
onComplete?.(action.toolCallId, {
|
|
27915
|
+
...action.state,
|
|
27916
|
+
otpCode: code,
|
|
27917
|
+
});
|
|
27918
|
+
}, 100);
|
|
27919
|
+
}
|
|
27920
|
+
}, disabled: isSubmitting }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleOtpSubmit, disabled: otpValues.join('').length !== 6, children: "Verify Code" }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: handleUseDifferentEmail, children: "Use different email" })] })] }));
|
|
27921
|
+
}
|
|
27922
|
+
// Phase 3: Options Menu (with inline cancel buttons and confirmation)
|
|
27923
|
+
if (phase === "awaiting_options") {
|
|
27924
|
+
const userAppointments = state.userAppointments || [];
|
|
27925
|
+
const maxAppointments = state.maxAppointmentsPerUser || 3;
|
|
27926
|
+
const appointmentCount = userAppointments.length;
|
|
27927
|
+
const canBook = appointmentCount < maxAppointments;
|
|
27928
|
+
const hasAppointments = appointmentCount > 0;
|
|
27929
|
+
const displayError = state.errorMessage || selectionError;
|
|
27930
|
+
// If confirming cancellation, show confirmation dialog
|
|
27931
|
+
if (selectedId) {
|
|
27932
|
+
const appointmentToCancel = userAppointments.find(appt => appt.id === selectedId);
|
|
27933
|
+
if (!appointmentToCancel) {
|
|
27934
|
+
setSelectedId(null); // Reset if appointment not found
|
|
27935
|
+
}
|
|
27936
|
+
else {
|
|
27937
|
+
return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Confirm Cancellation"] }), jsxs("div", { className: "ai-chat-action-body", children: [jsx("div", { className: "ai-chat-action-hint", children: "Are you sure you want to cancel this appointment?" }), jsx("div", { className: "ai-chat-action-appointment-item", style: { marginBottom: '16px' }, children: jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsx("div", { className: "ai-chat-action-appointment-subject", children: appointmentToCancel.subject }), jsx("div", { className: "ai-chat-action-appointment-time", children: appointmentToCancel.displayTime })] }) }), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsxs("div", { className: "ai-chat-action-button-group", children: [jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
|
|
27938
|
+
setIsSubmitting(true);
|
|
27939
|
+
onComplete?.(action.toolCallId, {
|
|
27940
|
+
...action.state,
|
|
27941
|
+
selectedOption: "cancel",
|
|
27942
|
+
selectedAppointmentId: selectedId,
|
|
27943
|
+
});
|
|
27944
|
+
}, disabled: isSubmitting, children: isSubmitting ? 'Cancelling...' : 'Confirm Cancellation' }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
27945
|
+
setSelectedId(null);
|
|
27946
|
+
setSelectionError(null);
|
|
27947
|
+
}, disabled: isSubmitting, children: "Go Back" })] })] })] }));
|
|
27948
|
+
}
|
|
27949
|
+
}
|
|
27950
|
+
// Normal view with inline cancel buttons
|
|
27951
|
+
return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Manage Your Appointments"] }), jsxs("div", { className: "ai-chat-action-body", children: [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 && (jsxs("div", { className: "ai-chat-action-appointment-list", children: [jsx("div", { className: "ai-chat-action-label", children: "Your Upcoming Appointments" }), userAppointments.map((appt) => (jsxs("div", { className: "ai-chat-action-appointment-item", children: [jsxs("div", { className: "ai-chat-action-appointment-info", children: [jsx("div", { className: "ai-chat-action-appointment-subject", children: appt.subject }), jsx("div", { className: "ai-chat-action-appointment-time", children: appt.displayTime })] }), jsx("button", { className: "ai-chat-action-button-secondary", type: "button", onClick: () => {
|
|
27952
|
+
setSelectedId(appt.id);
|
|
27953
|
+
setSelectionError(null);
|
|
27954
|
+
}, children: "Cancel" })] }, appt.id)))] })), displayError && (jsx("div", { className: "ai-chat-action-error", children: displayError })), canBook && (jsx("button", { className: "ai-chat-action-button", type: "button", onClick: () => {
|
|
27955
|
+
setIsSubmitting(true);
|
|
27956
|
+
onComplete?.(action.toolCallId, {
|
|
27957
|
+
...action.state,
|
|
27958
|
+
selectedOption: "book",
|
|
27959
|
+
});
|
|
27960
|
+
}, disabled: isSubmitting, children: isSubmitting ? 'Loading...' : 'Book New Appointment' })), !canBook && !hasAppointments && (jsx("div", { className: "ai-chat-action-hint", children: "No appointments found." }))] })] }));
|
|
27961
|
+
}
|
|
27962
|
+
// Phase 4: Appointment Selection (Booking)
|
|
27963
|
+
if (phase === "awaiting_booking") {
|
|
27964
|
+
const displayError = state.errorMessage || selectionError;
|
|
27965
|
+
return (jsxs("div", { className: `ai-chat-action-card ${className}`, style: accentStyle, children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx(CalendarIcon, {}), "Select Appointment Time"] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), 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) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
|
|
27966
|
+
setSelectedDate(date);
|
|
27967
|
+
setSelectedSlot(null);
|
|
27968
|
+
}, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (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 && (jsx("div", { className: "ai-chat-action-error", children: displayError })), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: handleAppointmentConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
|
|
27969
|
+
}
|
|
27970
|
+
// Fallback
|
|
27971
|
+
return null;
|
|
27522
27972
|
}
|
|
27523
27973
|
|
|
27524
27974
|
function truncate(text, maxLength) {
|
|
@@ -27529,17 +27979,30 @@ function truncate(text, maxLength) {
|
|
|
27529
27979
|
function ExternalLinkIcon() {
|
|
27530
27980
|
return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }), jsx("polyline", { points: "15 3 21 3 21 9" }), jsx("line", { x1: "10", y1: "14", x2: "21", y2: "3" })] }));
|
|
27531
27981
|
}
|
|
27982
|
+
function SingleLinkPreview({ link, onLinkClick, accentColor }) {
|
|
27983
|
+
const domain = (() => {
|
|
27984
|
+
if (!link.url)
|
|
27985
|
+
return '';
|
|
27986
|
+
try {
|
|
27987
|
+
return new URL(link.url).hostname.replace('www.', '');
|
|
27988
|
+
}
|
|
27989
|
+
catch {
|
|
27990
|
+
return link.url;
|
|
27991
|
+
}
|
|
27992
|
+
})();
|
|
27993
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
27994
|
+
return (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 && (jsx("div", { className: "ai-chat-link-preview__image", children: jsx("img", { src: link.image, alt: link.title, onError: (e) => {
|
|
27995
|
+
e.currentTarget.parentElement.style.display = 'none';
|
|
27996
|
+
} }) })), jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxs("div", { className: "ai-chat-link-preview__site", children: [link.favicon && (jsx("img", { src: link.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
|
|
27997
|
+
e.currentTarget.style.display = 'none';
|
|
27998
|
+
} })), jsx("span", { className: "ai-chat-link-preview__domain", children: link.siteName || domain })] }), jsx("h4", { className: "ai-chat-link-preview__title", children: link.title }), link.description && (jsx("p", { className: "ai-chat-link-preview__description", children: truncate(link.description, 120) }))] }), jsx("div", { className: "ai-chat-link-preview__arrow", children: jsx(ExternalLinkIcon, {}) })] }));
|
|
27999
|
+
}
|
|
27532
28000
|
function LinkPreviewCard({ action, onComplete, accentColor }) {
|
|
27533
28001
|
const rawState = action.state;
|
|
27534
28002
|
const hasCompletedRef = useRef(false);
|
|
27535
28003
|
// Provide safe defaults if state is missing
|
|
27536
28004
|
const state = {
|
|
27537
|
-
|
|
27538
|
-
title: rawState?.title || 'Link',
|
|
27539
|
-
description: rawState?.description,
|
|
27540
|
-
image: rawState?.image,
|
|
27541
|
-
siteName: rawState?.siteName,
|
|
27542
|
-
favicon: rawState?.favicon,
|
|
28005
|
+
links: rawState?.links || [],
|
|
27543
28006
|
context: rawState?.context,
|
|
27544
28007
|
status: rawState?.status || 'displaying',
|
|
27545
28008
|
error: rawState?.error,
|
|
@@ -27547,34 +28010,29 @@ function LinkPreviewCard({ action, onComplete, accentColor }) {
|
|
|
27547
28010
|
const isError = state.status === 'error';
|
|
27548
28011
|
// Auto-complete on mount so AI can continue generating text response
|
|
27549
28012
|
useEffect(() => {
|
|
27550
|
-
if (!action.done && !hasCompletedRef.current && onComplete && state.
|
|
28013
|
+
if (!action.done && !hasCompletedRef.current && onComplete && state.links.length > 0) {
|
|
27551
28014
|
hasCompletedRef.current = true;
|
|
27552
28015
|
// Signal completion immediately - the card is displayed, AI can continue
|
|
27553
28016
|
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
27554
28017
|
}
|
|
27555
28018
|
}, [action.done, action.toolCallId, onComplete, state]);
|
|
27556
|
-
const
|
|
27557
|
-
if (
|
|
27558
|
-
window.open(
|
|
28019
|
+
const handleLinkClick = (url) => {
|
|
28020
|
+
if (url) {
|
|
28021
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
27559
28022
|
}
|
|
27560
28023
|
onComplete?.(action.toolCallId, { ...state, status: 'clicked' });
|
|
27561
28024
|
};
|
|
27562
|
-
|
|
27563
|
-
|
|
27564
|
-
|
|
27565
|
-
|
|
27566
|
-
|
|
27567
|
-
|
|
27568
|
-
|
|
27569
|
-
|
|
27570
|
-
|
|
27571
|
-
|
|
27572
|
-
|
|
27573
|
-
return (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 && (jsx("div", { className: "ai-chat-link-preview__image", children: jsx("img", { src: state.image, alt: state.title, onError: (e) => {
|
|
27574
|
-
e.currentTarget.parentElement.style.display = 'none';
|
|
27575
|
-
} }) })), jsxs("div", { className: "ai-chat-link-preview__content", children: [jsxs("div", { className: "ai-chat-link-preview__site", children: [state.favicon && (jsx("img", { src: state.favicon, alt: "", className: "ai-chat-link-preview__favicon", onError: (e) => {
|
|
27576
|
-
e.currentTarget.style.display = 'none';
|
|
27577
|
-
} })), jsx("span", { className: "ai-chat-link-preview__domain", children: state.siteName || domain })] }), jsx("h4", { className: "ai-chat-link-preview__title", children: state.title }), state.description && (jsx("p", { className: "ai-chat-link-preview__description", children: truncate(state.description, 120) })), state.context && (jsx("p", { className: "ai-chat-link-preview__context", children: state.context })), isError && state.error && (jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error }))] }), jsx("div", { className: "ai-chat-link-preview__arrow", children: jsx(ExternalLinkIcon, {}) })] }));
|
|
28025
|
+
if (isError) {
|
|
28026
|
+
return (jsx("div", { className: "ai-chat-action-card ai-chat-link-preview ai-chat-link-preview--error", children: jsx("div", { className: "ai-chat-link-preview__content", children: jsx("p", { className: "ai-chat-link-preview__error-text", children: state.error || 'Failed to load preview' }) }) }));
|
|
28027
|
+
}
|
|
28028
|
+
if (state.links.length === 0) {
|
|
28029
|
+
return null;
|
|
28030
|
+
}
|
|
28031
|
+
return (jsxs("div", { className: "ai-chat-link-preview-container", children: [state.context && (jsx("p", { className: "ai-chat-link-preview__context", style: { marginBottom: '8px', fontSize: '0.9em', color: 'var(--ai-chat-fg-muted)' }, children: state.context })), jsx("div", { className: "ai-chat-link-preview-grid", style: {
|
|
28032
|
+
display: 'grid',
|
|
28033
|
+
gridTemplateColumns: state.links.length === 1 ? '1fr' : state.links.length === 2 ? 'repeat(2, 1fr)' : 'repeat(3, 1fr)',
|
|
28034
|
+
gap: '12px',
|
|
28035
|
+
}, children: state.links.map((link, index) => (jsx(SingleLinkPreview, { link: link, onLinkClick: () => handleLinkClick(link.url), accentColor: accentColor }, index))) })] }));
|
|
27578
28036
|
}
|
|
27579
28037
|
|
|
27580
28038
|
function PlayIcon() {
|
|
@@ -27640,7 +28098,7 @@ function VideoPlayerCard({ action, onComplete, accentColor }) {
|
|
|
27640
28098
|
return src;
|
|
27641
28099
|
}
|
|
27642
28100
|
};
|
|
27643
|
-
return (jsxs("div", { className: "ai-chat-
|
|
28101
|
+
return (jsxs("div", { className: "ai-chat-action-card ai-chat-video-player", style: style, children: [jsx("div", { className: "ai-chat-video-player__container", children: isError ? (jsx("div", { className: "ai-chat-video-player__error", children: jsx("span", { children: state.error || 'Could not load video' }) })) : !isPlaying && state.thumbnailUrl ? (jsxs("div", { className: "ai-chat-video-player__thumbnail", onClick: handlePlay, children: [jsx("img", { src: state.thumbnailUrl, alt: state.title || 'Video thumbnail' }), jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : !isPlaying ? (jsxs("div", { className: "ai-chat-video-player__placeholder", onClick: handlePlay, children: [jsx("button", { className: "ai-chat-video-player__play-btn", "aria-label": "Play video", children: jsx(PlayIcon, {}) }), jsx("span", { className: "ai-chat-video-player__click-text", children: "Click to play" }), jsx("div", { className: "ai-chat-video-player__provider-badge", children: getProviderLabel(state.provider) })] })) : state.provider === 'direct' ? (jsx("video", { src: state.embedUrl, controls: true, autoPlay: true, className: "ai-chat-video-player__video" })) : (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 && (jsx("div", { className: "ai-chat-video-player__context", children: state.context }))] }));
|
|
27644
28102
|
}
|
|
27645
28103
|
|
|
27646
28104
|
function MapPinIcon() {
|
|
@@ -27701,7 +28159,9 @@ function LocationItem({ location, settings, accentColor, onDirections, showMap =
|
|
|
27701
28159
|
}
|
|
27702
28160
|
};
|
|
27703
28161
|
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
27704
|
-
|
|
28162
|
+
// Use smaller map height in compact mode
|
|
28163
|
+
const effectiveMapHeight = compact ? Math.min(mapHeight, 140) : mapHeight;
|
|
28164
|
+
return (jsxs("div", { className: `ai-chat-action-card ai-chat-location-card ${compact ? 'ai-chat-location-card--compact' : ''}`, style: style, children: [showMap && settings.showMap !== false && (jsx("div", { className: "ai-chat-location-card__map", style: { height: effectiveMapHeight }, children: jsx("iframe", { src: getMapEmbedUrl(), allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade", title: `Map of ${location.name}` }) })), jsxs("div", { className: "ai-chat-location-card__content", children: [jsxs("div", { className: "ai-chat-location-card__header", children: [jsx("h4", { className: "ai-chat-location-card__name", children: location.name }), location.type && (jsx("span", { className: "ai-chat-location-card__type", children: location.type })), openStatus !== null && (jsx("span", { className: `ai-chat-location-card__status ai-chat-location-card__status--${openStatus ? 'open' : 'closed'}`, children: openStatus ? 'Open' : 'Closed' }))] }), jsxs("p", { className: "ai-chat-location-card__address", children: [jsx(MapPinIcon, {}), location.address] }), location.description && (jsx("p", { className: "ai-chat-location-card__description", children: location.description })), settings.showHours !== false && location.hours && location.hours.length > 0 && (jsx(HoursDisplay, { hours: location.hours, compact: compact })), settings.showPhone !== false && location.phone && (jsxs("button", { type: "button", className: "ai-chat-location-card__phone", onClick: handleCall, children: [jsx(PhoneIcon, {}), location.phone] })), jsxs("div", { className: "ai-chat-location-card__actions", children: [settings.showDirectionsButton !== false && (jsxs("button", { type: "button", className: "ai-chat-location-card__button", style: accentColor ? { backgroundColor: accentColor } : undefined, onClick: onDirections, children: [jsx(NavigationIcon, {}), compact ? 'Directions' : 'Get Directions'] })), !compact && location.website && (jsxs("a", { href: location.website, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-location-card__link", children: [jsx(GlobeIcon, {}), "Website"] }))] })] })] }));
|
|
27705
28165
|
}
|
|
27706
28166
|
function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
27707
28167
|
const rawState = action.state;
|
|
@@ -27735,9 +28195,197 @@ function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
|
27735
28195
|
if (isSingleLocation) {
|
|
27736
28196
|
return (jsx(LocationItem, { location: locations[0], settings: settings, accentColor: accentColor, onDirections: () => handleDirections(locations[0]), showMap: true }));
|
|
27737
28197
|
}
|
|
27738
|
-
return (jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsx(MapPinIcon, {}), jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsx("div", { className:
|
|
28198
|
+
return (jsxs("div", { className: `ai-chat-location-card-list ai-chat-location-card-list--${layout}`, children: [jsxs("div", { className: "ai-chat-location-card-list__header", children: [jsx(MapPinIcon, {}), jsxs("span", { children: [locations.length, " Locations"] })] }), layout === 'stack' && (jsx("div", { className: `ai-chat-location-card-list__stack ai-chat-location-card-list__stack--cols-${stackColumns}`, children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: settings.showMap !== false, compact: locations.length > 2 }, location.id))) })), layout === 'grid' && (jsx("div", { className: "ai-chat-location-card-list__grid", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: false, compact: true }, location.id))) })), layout === 'carousel' && (jsx("div", { className: "ai-chat-location-card-list__carousel", children: locations.map((location) => (jsx(LocationItem, { location: location, settings: settings, accentColor: accentColor, onDirections: () => handleDirections(location), showMap: true, compact: false }, location.id))) }))] }));
|
|
28199
|
+
}
|
|
28200
|
+
|
|
28201
|
+
function UsersIcon() {
|
|
28202
|
+
return (jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }), jsx("circle", { cx: "9", cy: "7", r: "4" }), jsx("path", { d: "M22 21v-2a4 4 0 0 0-3-3.87" }), jsx("path", { d: "M16 3.13a4 4 0 0 1 0 7.75" })] }));
|
|
28203
|
+
}
|
|
28204
|
+
const AVATAR_COLORS = [
|
|
28205
|
+
{ bg: '#E8F5E9', text: '#2E7D32' }, // Green
|
|
28206
|
+
{ bg: '#E3F2FD', text: '#1565C0' }, // Blue
|
|
28207
|
+
{ bg: '#FFF3E0', text: '#E65100' }, // Orange
|
|
28208
|
+
{ bg: '#F3E5F5', text: '#7B1FA2' }, // Purple
|
|
28209
|
+
{ bg: '#FFEBEE', text: '#C62828' }, // Red
|
|
28210
|
+
{ bg: '#E0F7FA', text: '#00838F' }, // Cyan
|
|
28211
|
+
{ bg: '#FFF8E1', text: '#F9A825' }, // Amber
|
|
28212
|
+
{ bg: '#FCE4EC', text: '#AD1457' }, // Pink
|
|
28213
|
+
];
|
|
28214
|
+
function getInitials(name) {
|
|
28215
|
+
const parts = name.trim().split(/\s+/);
|
|
28216
|
+
if (parts.length === 1) {
|
|
28217
|
+
return parts[0].substring(0, 2).toUpperCase();
|
|
28218
|
+
}
|
|
28219
|
+
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
|
|
28220
|
+
}
|
|
28221
|
+
function getColorFromName(name) {
|
|
28222
|
+
let hash = 0;
|
|
28223
|
+
for (let i = 0; i < name.length; i++) {
|
|
28224
|
+
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
|
28225
|
+
}
|
|
28226
|
+
return AVATAR_COLORS[Math.abs(hash) % AVATAR_COLORS.length];
|
|
28227
|
+
}
|
|
28228
|
+
function ContactItem({ contact, settings, accentColor, onEmail, onPhone, compact = false, layout = 'vertical', }) {
|
|
28229
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
28230
|
+
const layoutClass = layout === 'horizontal'
|
|
28231
|
+
? 'ai-chat-contact-card--horizontal'
|
|
28232
|
+
: 'ai-chat-contact-card--vertical';
|
|
28233
|
+
return (jsxs("div", { className: `ai-chat-action-card ai-chat-contact-card ${layoutClass} ${compact ? 'ai-chat-contact-card--compact' : ''}`, style: style, children: [jsxs("div", { className: "ai-chat-contact-card__image-section", children: [contact.profilePictureUrl ? (jsx("img", { src: contact.profilePictureUrl, alt: contact.name, className: "ai-chat-contact-card__image", onError: (e) => {
|
|
28234
|
+
e.currentTarget.style.display = 'none';
|
|
28235
|
+
const placeholder = e.currentTarget.parentElement?.querySelector('.ai-chat-contact-card__initials');
|
|
28236
|
+
if (placeholder) {
|
|
28237
|
+
placeholder.style.display = 'flex';
|
|
28238
|
+
}
|
|
28239
|
+
} })) : null, (() => {
|
|
28240
|
+
const colors = getColorFromName(contact.name);
|
|
28241
|
+
return (jsx("div", { className: "ai-chat-contact-card__initials", style: {
|
|
28242
|
+
display: contact.profilePictureUrl ? 'none' : 'flex',
|
|
28243
|
+
backgroundColor: colors.bg,
|
|
28244
|
+
color: colors.text,
|
|
28245
|
+
}, children: getInitials(contact.name) }));
|
|
28246
|
+
})()] }), jsxs("div", { className: "ai-chat-contact-card__info", children: [jsx("h4", { className: "ai-chat-contact-card__name", children: contact.name }), settings.showRole !== false && contact.role && (jsx("p", { className: "ai-chat-contact-card__role", children: contact.role })), jsxs("div", { className: "ai-chat-contact-card__details", children: [settings.showEmail !== false && contact.email && (jsx("a", { href: `mailto:${contact.email}`, className: "ai-chat-contact-card__detail", onClick: onEmail, children: contact.email })), settings.showPhone !== false && contact.phone && (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 && (jsxs("div", { className: "ai-chat-contact-card__responsibilities", children: [contact.responsibilities.slice(0, 3).map((resp, idx) => (jsx("span", { className: "ai-chat-contact-card__responsibility-tag", children: resp }, idx))), contact.responsibilities.length > 3 && (jsxs("span", { className: "ai-chat-contact-card__responsibility-more", children: ["+", contact.responsibilities.length - 3, " more"] }))] }))] })] }));
|
|
28247
|
+
}
|
|
28248
|
+
function ContactCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
28249
|
+
const rawState = action.state;
|
|
28250
|
+
const hasCompletedRef = useRef(false);
|
|
28251
|
+
const state = {
|
|
28252
|
+
contacts: rawState?.contacts || [],
|
|
28253
|
+
settings: rawState?.settings || {},
|
|
28254
|
+
query: rawState?.query,
|
|
28255
|
+
status: rawState?.status || 'displaying',
|
|
28256
|
+
};
|
|
28257
|
+
const { contacts, settings } = state;
|
|
28258
|
+
const isSingleContact = contacts.length === 1;
|
|
28259
|
+
const stackColumns = Math.min(Math.max(contacts.length, 1), maxColumns);
|
|
28260
|
+
useEffect(() => {
|
|
28261
|
+
if (!action.done && !hasCompletedRef.current && onComplete) {
|
|
28262
|
+
hasCompletedRef.current = true;
|
|
28263
|
+
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
28264
|
+
}
|
|
28265
|
+
}, [action.done, action.toolCallId, onComplete, state]);
|
|
28266
|
+
const handleContact = () => {
|
|
28267
|
+
onComplete?.(action.toolCallId, { ...state, status: 'contacted' });
|
|
28268
|
+
};
|
|
28269
|
+
if (contacts.length === 0) {
|
|
28270
|
+
return (jsxs("div", { className: "ai-chat-contact-card ai-chat-contact-card--empty", children: [jsx("div", { className: "ai-chat-contact-card__empty-icon", children: jsx(UsersIcon, {}) }), jsxs("p", { className: "ai-chat-contact-card__empty-text", children: ["No contacts found", state.query ? ` for "${state.query}"` : ''] })] }));
|
|
28271
|
+
}
|
|
28272
|
+
if (isSingleContact) {
|
|
28273
|
+
return (jsx(ContactItem, { contact: contacts[0], settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, layout: settings.layout || 'horizontal' }));
|
|
28274
|
+
}
|
|
28275
|
+
const isWidget = maxColumns === 1;
|
|
28276
|
+
const stackClassName = isWidget
|
|
28277
|
+
? 'ai-chat-contact-card-list__stack ai-chat-contact-card-list__stack--widget'
|
|
28278
|
+
: 'ai-chat-contact-card-list__stack';
|
|
28279
|
+
return (jsxs("div", { className: "ai-chat-contact-card-list", style: { containerType: 'inline-size' }, children: [jsxs("div", { className: "ai-chat-contact-card-list__header", children: [jsx(UsersIcon, {}), jsxs("span", { children: [contacts.length, " Contacts"] })] }), jsx("div", { className: stackClassName, style: isWidget ? undefined : {
|
|
27739
28280
|
gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
|
|
27740
|
-
}, children:
|
|
28281
|
+
}, children: contacts.map((contact) => (jsx(ContactItem, { contact: contact, settings: settings, accentColor: accentColor, onEmail: handleContact, onPhone: handleContact, compact: true, layout: settings.layout || 'vertical' }, contact.id))) })] }));
|
|
28282
|
+
}
|
|
28283
|
+
|
|
28284
|
+
function FormCard({ action, onComplete, accentColor }) {
|
|
28285
|
+
const state = action.state;
|
|
28286
|
+
const [currentStep, setCurrentStep] = useState(0);
|
|
28287
|
+
const [answers, setAnswers] = useState({});
|
|
28288
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
28289
|
+
const questions = state.questions || [];
|
|
28290
|
+
const currentQuestion = questions[currentStep];
|
|
28291
|
+
const totalQuestions = questions.length;
|
|
28292
|
+
const handleAnswerChange = (questionId, value) => {
|
|
28293
|
+
setAnswers((prev) => ({ ...prev, [questionId]: value }));
|
|
28294
|
+
};
|
|
28295
|
+
const handleNext = () => {
|
|
28296
|
+
if (currentStep < totalQuestions - 1) {
|
|
28297
|
+
setCurrentStep((prev) => prev + 1);
|
|
28298
|
+
}
|
|
28299
|
+
};
|
|
28300
|
+
const handlePrev = () => {
|
|
28301
|
+
if (currentStep > 0) {
|
|
28302
|
+
setCurrentStep((prev) => prev - 1);
|
|
28303
|
+
}
|
|
28304
|
+
};
|
|
28305
|
+
const handleSubmit = () => {
|
|
28306
|
+
if (!onComplete)
|
|
28307
|
+
return;
|
|
28308
|
+
setIsSubmitting(true);
|
|
28309
|
+
const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({
|
|
28310
|
+
questionId,
|
|
28311
|
+
value,
|
|
28312
|
+
}));
|
|
28313
|
+
onComplete(action.toolCallId, {
|
|
28314
|
+
...state,
|
|
28315
|
+
status: 'submitted',
|
|
28316
|
+
answers: formattedAnswers,
|
|
28317
|
+
});
|
|
28318
|
+
};
|
|
28319
|
+
const handleSkip = () => {
|
|
28320
|
+
if (!onComplete || !state.settings.allowSkip)
|
|
28321
|
+
return;
|
|
28322
|
+
onComplete(action.toolCallId, {
|
|
28323
|
+
...state,
|
|
28324
|
+
status: 'skipped',
|
|
28325
|
+
});
|
|
28326
|
+
};
|
|
28327
|
+
const isCurrentAnswered = () => {
|
|
28328
|
+
if (!currentQuestion)
|
|
28329
|
+
return false;
|
|
28330
|
+
const answer = answers[currentQuestion.id];
|
|
28331
|
+
if (!answer)
|
|
28332
|
+
return !currentQuestion.required;
|
|
28333
|
+
if (Array.isArray(answer))
|
|
28334
|
+
return answer.length > 0 || !currentQuestion.required;
|
|
28335
|
+
return answer.trim() !== '' || !currentQuestion.required;
|
|
28336
|
+
};
|
|
28337
|
+
const canSubmit = () => {
|
|
28338
|
+
return questions.every((q) => {
|
|
28339
|
+
const answer = answers[q.id];
|
|
28340
|
+
if (!q.required)
|
|
28341
|
+
return true;
|
|
28342
|
+
if (!answer)
|
|
28343
|
+
return false;
|
|
28344
|
+
if (Array.isArray(answer))
|
|
28345
|
+
return answer.length > 0;
|
|
28346
|
+
return answer.trim() !== '';
|
|
28347
|
+
});
|
|
28348
|
+
};
|
|
28349
|
+
// Error state
|
|
28350
|
+
if (state.status === 'error') {
|
|
28351
|
+
return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--error", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "ai-chat-form-card__title", children: "Form Error" })] }), jsx("p", { className: "ai-chat-form-card__error", children: state.error || 'Could not load form' })] }));
|
|
28352
|
+
}
|
|
28353
|
+
// Submitted state
|
|
28354
|
+
if (state.status === 'submitted' || action.done) {
|
|
28355
|
+
return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--submitted", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u2713" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__success", children: state.settings.successMessage || 'Thank you for your response!' })] }));
|
|
28356
|
+
}
|
|
28357
|
+
// Skipped state
|
|
28358
|
+
if (state.status === 'skipped') {
|
|
28359
|
+
return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--skipped", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\u21B7" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__skipped-text", children: "Form skipped" })] }));
|
|
28360
|
+
}
|
|
28361
|
+
// No questions
|
|
28362
|
+
if (totalQuestions === 0) {
|
|
28363
|
+
return (jsxs("div", { className: "ai-chat-form-card ai-chat-form-card--empty", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), jsx("p", { className: "ai-chat-form-card__empty-text", children: "This form has no questions." })] }));
|
|
28364
|
+
}
|
|
28365
|
+
return (jsxs("div", { className: "ai-chat-form-card", children: [jsxs("div", { className: "ai-chat-form-card__header", children: [jsx("span", { className: "ai-chat-form-card__icon", children: "\uD83D\uDCCB" }), jsx("span", { className: "ai-chat-form-card__title", children: state.title })] }), state.description && (jsx("p", { className: "ai-chat-form-card__description", children: state.description })), state.context && (jsx("p", { className: "ai-chat-form-card__context", children: state.context })), state.settings.showProgress && (jsxs("div", { className: "ai-chat-form-card__progress", children: [jsx("div", { className: "ai-chat-form-card__progress-bar", style: {
|
|
28366
|
+
width: `${((currentStep + 1) / totalQuestions) * 100}%`,
|
|
28367
|
+
backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
|
|
28368
|
+
} }), jsxs("span", { className: "ai-chat-form-card__progress-text", children: [currentStep + 1, " of ", totalQuestions] })] })), jsxs("div", { className: "ai-chat-form-card__question", children: [jsxs("p", { className: "ai-chat-form-card__question-text", children: [currentQuestion.text, currentQuestion.required && jsx("span", { className: "ai-chat-form-card__required", children: "*" })] }), jsxs("div", { className: "ai-chat-form-card__answer", children: [currentQuestion.type === 'text' && (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 && (jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => (jsxs("label", { className: "ai-chat-form-card__option", children: [jsx("input", { type: "radio", name: currentQuestion.id, value: option.value, checked: answers[currentQuestion.id] === option.value, onChange: () => handleAnswerChange(currentQuestion.id, option.value) }), jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id))) })), currentQuestion.type === 'multiple_choice' && currentQuestion.options && (jsx("div", { className: "ai-chat-form-card__options", children: currentQuestion.options.map((option) => {
|
|
28369
|
+
const currentAnswers = answers[currentQuestion.id] || [];
|
|
28370
|
+
const isChecked = currentAnswers.includes(option.value);
|
|
28371
|
+
return (jsxs("label", { className: "ai-chat-form-card__option", children: [jsx("input", { type: "checkbox", value: option.value, checked: isChecked, onChange: () => {
|
|
28372
|
+
const newAnswers = isChecked
|
|
28373
|
+
? currentAnswers.filter((v) => v !== option.value)
|
|
28374
|
+
: [...currentAnswers, option.value];
|
|
28375
|
+
handleAnswerChange(currentQuestion.id, newAnswers);
|
|
28376
|
+
} }), jsx("span", { className: "ai-chat-form-card__option-text", children: option.text })] }, option.id));
|
|
28377
|
+
}) })), currentQuestion.type === 'rating' && (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) => (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: {
|
|
28378
|
+
borderColor: answers[currentQuestion.id] === String(rating)
|
|
28379
|
+
? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
|
|
28380
|
+
: undefined,
|
|
28381
|
+
backgroundColor: answers[currentQuestion.id] === String(rating)
|
|
28382
|
+
? (accentColor || 'var(--ai-chat-accent-color, #3b82f6)')
|
|
28383
|
+
: undefined,
|
|
28384
|
+
}, children: rating }, rating))) }))] })] }), jsxs("div", { className: "ai-chat-form-card__actions", children: [currentStep > 0 && (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 && (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--ghost", onClick: handleSkip, children: "Skip" })), jsx("div", { className: "ai-chat-form-card__actions-spacer" }), currentStep < totalQuestions - 1 ? (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleNext, disabled: !isCurrentAnswered(), style: {
|
|
28385
|
+
backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
|
|
28386
|
+
}, children: "Next" })) : (jsx("button", { type: "button", className: "ai-chat-form-card__btn ai-chat-form-card__btn--primary", onClick: handleSubmit, disabled: !canSubmit() || isSubmitting, style: {
|
|
28387
|
+
backgroundColor: accentColor || 'var(--ai-chat-accent-color, #3b82f6)',
|
|
28388
|
+
}, children: isSubmitting ? 'Submitting...' : (state.settings.submitButtonText || 'Submit') }))] })] }));
|
|
27741
28389
|
}
|
|
27742
28390
|
|
|
27743
28391
|
const pendingResolvers = new Map();
|
|
@@ -27750,12 +28398,6 @@ function getFrontendActionHandler(implementation) {
|
|
|
27750
28398
|
function getActionRenderer(implementation) {
|
|
27751
28399
|
return actionRenderers[implementation];
|
|
27752
28400
|
}
|
|
27753
|
-
function getActionPrompt(implementation) {
|
|
27754
|
-
if (implementation === "google-calendar-appointment") {
|
|
27755
|
-
return "Select a date to continue.";
|
|
27756
|
-
}
|
|
27757
|
-
return "Action input required.";
|
|
27758
|
-
}
|
|
27759
28401
|
function waitForActionState(toolCallId) {
|
|
27760
28402
|
return new Promise((resolve) => {
|
|
27761
28403
|
pendingResolvers.set(toolCallId, resolve);
|
|
@@ -27796,7 +28438,7 @@ function registerGoogleCalendarAction() {
|
|
|
27796
28438
|
// Register the handler
|
|
27797
28439
|
registerGoogleCalendarHandler();
|
|
27798
28440
|
// Register the renderer
|
|
27799
|
-
actionRenderers["google-calendar-appointment"] = (message) => {
|
|
28441
|
+
actionRenderers["google-calendar-appointment"] = (message, accentColor) => {
|
|
27800
28442
|
const action = message.action;
|
|
27801
28443
|
if (!action)
|
|
27802
28444
|
return null;
|
|
@@ -27810,22 +28452,54 @@ function registerGoogleCalendarAction() {
|
|
|
27810
28452
|
input: action.input,
|
|
27811
28453
|
state: action.state,
|
|
27812
28454
|
done: action.done ?? false,
|
|
27813
|
-
}, onComplete: handleComplete }));
|
|
28455
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
28456
|
+
};
|
|
28457
|
+
}
|
|
28458
|
+
|
|
28459
|
+
function registerMicrosoftCalendarHandler() {
|
|
28460
|
+
frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
|
|
28461
|
+
return waitForActionState(context.toolCallId);
|
|
27814
28462
|
};
|
|
27815
28463
|
}
|
|
27816
28464
|
|
|
27817
28465
|
/**
|
|
27818
|
-
* Register
|
|
28466
|
+
* Register microsoft-calendar-appointment action handler and renderer.
|
|
27819
28467
|
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
27820
28468
|
*/
|
|
27821
|
-
function
|
|
27822
|
-
//
|
|
27823
|
-
|
|
27824
|
-
|
|
27825
|
-
|
|
27826
|
-
|
|
27827
|
-
|
|
27828
|
-
|
|
28469
|
+
function registerMicrosoftCalendarAction() {
|
|
28470
|
+
// Register the handler
|
|
28471
|
+
registerMicrosoftCalendarHandler();
|
|
28472
|
+
// Register the renderer
|
|
28473
|
+
actionRenderers["microsoft-calendar-appointment"] = (message, accentColor) => {
|
|
28474
|
+
const action = message.action;
|
|
28475
|
+
if (!action)
|
|
28476
|
+
return null;
|
|
28477
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28478
|
+
resolveActionState(toolCallId, newState);
|
|
28479
|
+
};
|
|
28480
|
+
return (jsx(MicrosoftCalendarCard, { action: {
|
|
28481
|
+
implementation: action.implementation,
|
|
28482
|
+
toolCallId: action.toolCallId,
|
|
28483
|
+
actionId: action.actionId,
|
|
28484
|
+
input: action.input,
|
|
28485
|
+
state: action.state,
|
|
28486
|
+
done: action.done ?? false,
|
|
28487
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
28488
|
+
};
|
|
28489
|
+
}
|
|
28490
|
+
|
|
28491
|
+
/**
|
|
28492
|
+
* Register link-preview action handler and renderer.
|
|
28493
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
28494
|
+
*/
|
|
28495
|
+
function registerLinkPreviewAction() {
|
|
28496
|
+
// Handler - auto-completes immediately since no user input is needed
|
|
28497
|
+
frontendActionHandlers["link-preview"] = async (_input, state, _context) => {
|
|
28498
|
+
return { ...state, status: "displaying" };
|
|
28499
|
+
};
|
|
28500
|
+
// Renderer - displays the link preview card
|
|
28501
|
+
actionRenderers["link-preview"] = (message, accentColor) => {
|
|
28502
|
+
const action = message.action;
|
|
27829
28503
|
if (!action)
|
|
27830
28504
|
return null;
|
|
27831
28505
|
const handleComplete = (toolCallId, newState) => {
|
|
@@ -27842,7 +28516,7 @@ function registerLinkPreviewAction() {
|
|
|
27842
28516
|
input: action.input,
|
|
27843
28517
|
state: action.state,
|
|
27844
28518
|
done: isDone,
|
|
27845
|
-
}, onComplete: handleComplete }));
|
|
28519
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
27846
28520
|
};
|
|
27847
28521
|
}
|
|
27848
28522
|
|
|
@@ -27856,7 +28530,7 @@ function registerVideoPlayerAction() {
|
|
|
27856
28530
|
return { ...state, status: "displaying" };
|
|
27857
28531
|
};
|
|
27858
28532
|
// Renderer - displays the embedded video player card
|
|
27859
|
-
actionRenderers["video-player"] = (message) => {
|
|
28533
|
+
actionRenderers["video-player"] = (message, accentColor) => {
|
|
27860
28534
|
const action = message.action;
|
|
27861
28535
|
if (!action)
|
|
27862
28536
|
return null;
|
|
@@ -27874,7 +28548,7 @@ function registerVideoPlayerAction() {
|
|
|
27874
28548
|
input: action.input,
|
|
27875
28549
|
state: action.state,
|
|
27876
28550
|
done: isDone,
|
|
27877
|
-
}, onComplete: handleComplete }));
|
|
28551
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
27878
28552
|
};
|
|
27879
28553
|
}
|
|
27880
28554
|
|
|
@@ -27888,7 +28562,7 @@ function registerLocationCardAction() {
|
|
|
27888
28562
|
return { ...state, status: "displaying" };
|
|
27889
28563
|
};
|
|
27890
28564
|
// Renderer - displays the location card
|
|
27891
|
-
actionRenderers["location-card"] = (message, accentColor) => {
|
|
28565
|
+
actionRenderers["location-card"] = (message, accentColor, variant) => {
|
|
27892
28566
|
const action = message.action;
|
|
27893
28567
|
if (!action)
|
|
27894
28568
|
return null;
|
|
@@ -27906,7 +28580,92 @@ function registerLocationCardAction() {
|
|
|
27906
28580
|
input: action.input,
|
|
27907
28581
|
state: action.state,
|
|
27908
28582
|
done: isDone,
|
|
27909
|
-
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: 1 }));
|
|
28583
|
+
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
28584
|
+
};
|
|
28585
|
+
}
|
|
28586
|
+
|
|
28587
|
+
function registerContactCardAction() {
|
|
28588
|
+
// Handler - auto-completes immediately since no user input is needed
|
|
28589
|
+
frontendActionHandlers['contact-card'] = async (_input, state, _context) => {
|
|
28590
|
+
return { ...state, status: 'displaying' };
|
|
28591
|
+
};
|
|
28592
|
+
// Renderer - displays the contact card
|
|
28593
|
+
actionRenderers['contact-card'] = (message, accentColor, variant) => {
|
|
28594
|
+
const action = message.action;
|
|
28595
|
+
if (!action)
|
|
28596
|
+
return null;
|
|
28597
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28598
|
+
resolveActionState(toolCallId, newState);
|
|
28599
|
+
};
|
|
28600
|
+
// Check if action state indicates it's already complete
|
|
28601
|
+
const state = action.state;
|
|
28602
|
+
const status = state?.status;
|
|
28603
|
+
const isDone = action.done || status === 'displaying' || status === 'contacted';
|
|
28604
|
+
return (jsx(ContactCard, { action: {
|
|
28605
|
+
implementation: action.implementation,
|
|
28606
|
+
toolCallId: action.toolCallId,
|
|
28607
|
+
actionId: action.actionId,
|
|
28608
|
+
input: action.input,
|
|
28609
|
+
state: action.state,
|
|
28610
|
+
done: isDone,
|
|
28611
|
+
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
28612
|
+
};
|
|
28613
|
+
}
|
|
28614
|
+
|
|
28615
|
+
function registerQueryContactDirectoryAction() {
|
|
28616
|
+
// Handler - auto-completes immediately since no user input is needed
|
|
28617
|
+
frontendActionHandlers['query-contact-directory'] = async (_input, state, _context) => {
|
|
28618
|
+
return { ...state, status: 'displaying' };
|
|
28619
|
+
};
|
|
28620
|
+
// Renderer - displays the contact card with search results
|
|
28621
|
+
actionRenderers['query-contact-directory'] = (message, accentColor, variant) => {
|
|
28622
|
+
const action = message.action;
|
|
28623
|
+
if (!action)
|
|
28624
|
+
return null;
|
|
28625
|
+
// Handle completion - triggers agent to continue with text response
|
|
28626
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28627
|
+
resolveActionState(toolCallId, newState);
|
|
28628
|
+
};
|
|
28629
|
+
// Check if action state indicates it's already complete
|
|
28630
|
+
const state = action.state;
|
|
28631
|
+
const status = state?.status;
|
|
28632
|
+
const isDone = action.done || status === 'displaying' || status === 'contacted';
|
|
28633
|
+
return (jsx(ContactCard, { action: {
|
|
28634
|
+
implementation: action.implementation,
|
|
28635
|
+
toolCallId: action.toolCallId,
|
|
28636
|
+
actionId: action.actionId,
|
|
28637
|
+
input: action.input,
|
|
28638
|
+
state: action.state,
|
|
28639
|
+
done: isDone,
|
|
28640
|
+
}, onComplete: handleComplete, accentColor: accentColor, maxColumns: variant === 'fullpage' ? 3 : 1 }));
|
|
28641
|
+
};
|
|
28642
|
+
}
|
|
28643
|
+
|
|
28644
|
+
function registerDisplayFormAction() {
|
|
28645
|
+
// Handler - handles form submission and state updates
|
|
28646
|
+
frontendActionHandlers['display-form'] = async (_input, _state, context) => {
|
|
28647
|
+
return waitForActionState(context.toolCallId);
|
|
28648
|
+
};
|
|
28649
|
+
// Renderer - displays the form card
|
|
28650
|
+
actionRenderers['display-form'] = (message, accentColor, variant) => {
|
|
28651
|
+
const action = message.action;
|
|
28652
|
+
if (!action)
|
|
28653
|
+
return null;
|
|
28654
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28655
|
+
resolveActionState(toolCallId, newState);
|
|
28656
|
+
};
|
|
28657
|
+
// Check if action state indicates it's already complete
|
|
28658
|
+
const state = action.state;
|
|
28659
|
+
const status = state?.status;
|
|
28660
|
+
const isDone = action.done || status === 'completed' || status === 'submitted';
|
|
28661
|
+
return (jsx(FormCard, { action: {
|
|
28662
|
+
implementation: action.implementation,
|
|
28663
|
+
toolCallId: action.toolCallId,
|
|
28664
|
+
actionId: action.actionId,
|
|
28665
|
+
input: action.input,
|
|
28666
|
+
state: action.state,
|
|
28667
|
+
done: isDone,
|
|
28668
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
27910
28669
|
};
|
|
27911
28670
|
}
|
|
27912
28671
|
|
|
@@ -27923,9 +28682,13 @@ function initializeActionHandlers() {
|
|
|
27923
28682
|
initialized = true;
|
|
27924
28683
|
// Explicitly call each registration function to prevent tree-shaking
|
|
27925
28684
|
registerGoogleCalendarAction();
|
|
28685
|
+
registerMicrosoftCalendarAction();
|
|
27926
28686
|
registerLinkPreviewAction();
|
|
27927
28687
|
registerVideoPlayerAction();
|
|
27928
28688
|
registerLocationCardAction();
|
|
28689
|
+
registerQueryContactDirectoryAction();
|
|
28690
|
+
registerContactCardAction();
|
|
28691
|
+
registerDisplayFormAction();
|
|
27929
28692
|
}
|
|
27930
28693
|
|
|
27931
28694
|
/**
|
|
@@ -28145,12 +28908,6 @@ function isStorageAvailable() {
|
|
|
28145
28908
|
}
|
|
28146
28909
|
}
|
|
28147
28910
|
|
|
28148
|
-
/**
|
|
28149
|
-
* useChat Hook
|
|
28150
|
-
* Main state management for chat functionality
|
|
28151
|
-
*/
|
|
28152
|
-
// Initialize action handlers immediately to prevent tree-shaking
|
|
28153
|
-
initializeActionHandlers();
|
|
28154
28911
|
function hydrateToolNames(messages) {
|
|
28155
28912
|
const toolCallNameById = new Map();
|
|
28156
28913
|
for (const entry of messages) {
|
|
@@ -28194,118 +28951,77 @@ function hydrateToolNames(messages) {
|
|
|
28194
28951
|
};
|
|
28195
28952
|
});
|
|
28196
28953
|
}
|
|
28197
|
-
function
|
|
28198
|
-
return messages
|
|
28199
|
-
if (entry.message.role !== "assistant" || !entry.action) {
|
|
28200
|
-
return entry;
|
|
28201
|
-
}
|
|
28202
|
-
const content = typeof entry.message.content === "string" ? entry.message.content : "";
|
|
28203
|
-
if (content.trim().length > 0) {
|
|
28204
|
-
return entry;
|
|
28205
|
-
}
|
|
28206
|
-
return {
|
|
28207
|
-
...entry,
|
|
28208
|
-
message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
|
|
28209
|
-
};
|
|
28210
|
-
});
|
|
28954
|
+
function hydrateMessages(messages) {
|
|
28955
|
+
return hydrateToolNames(messages);
|
|
28211
28956
|
}
|
|
28212
|
-
|
|
28213
|
-
|
|
28214
|
-
|
|
28215
|
-
|
|
28216
|
-
|
|
28217
|
-
|
|
28218
|
-
|
|
28219
|
-
|
|
28957
|
+
|
|
28958
|
+
function deriveErrorInfo(error) {
|
|
28959
|
+
if (error instanceof ApiError) {
|
|
28960
|
+
const retryAfterSeconds = typeof error.retryAfterMs === 'number'
|
|
28961
|
+
? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
|
|
28962
|
+
: undefined;
|
|
28963
|
+
const lowerMessage = (error.message || '').toLowerCase();
|
|
28964
|
+
let message;
|
|
28965
|
+
switch (error.status) {
|
|
28966
|
+
case 429: {
|
|
28967
|
+
const isPerUser = lowerMessage.includes('user');
|
|
28968
|
+
const base = isPerUser
|
|
28969
|
+
? 'You have reached the per-user rate limit.'
|
|
28970
|
+
: 'This widget has received too many requests.';
|
|
28971
|
+
if (retryAfterSeconds) {
|
|
28972
|
+
message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
|
|
28973
|
+
}
|
|
28974
|
+
else {
|
|
28975
|
+
message = `${base} Please wait a moment and try again.`;
|
|
28976
|
+
}
|
|
28977
|
+
break;
|
|
28978
|
+
}
|
|
28979
|
+
case 401:
|
|
28980
|
+
message = 'Authentication failed. Please refresh the page or verify your API key.';
|
|
28981
|
+
break;
|
|
28982
|
+
case 403:
|
|
28983
|
+
message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
|
|
28984
|
+
break;
|
|
28985
|
+
case 404:
|
|
28986
|
+
if (lowerMessage.includes('not active')) {
|
|
28987
|
+
message = 'This widget is currently inactive. Please contact the site owner.';
|
|
28988
|
+
}
|
|
28989
|
+
else {
|
|
28990
|
+
message = 'We could not find this widget. It may have been removed.';
|
|
28991
|
+
}
|
|
28992
|
+
break;
|
|
28993
|
+
default:
|
|
28994
|
+
if (error.status >= 500) {
|
|
28995
|
+
message = 'The server encountered an error. Please try again shortly.';
|
|
28996
|
+
}
|
|
28997
|
+
else if (error.status > 0) {
|
|
28998
|
+
message = error.message || 'Something went wrong. Please try again.';
|
|
28999
|
+
}
|
|
29000
|
+
else {
|
|
29001
|
+
message = error.message || 'Unable to connect to the server. Please check your internet connection.';
|
|
29002
|
+
}
|
|
28220
29003
|
}
|
|
28221
|
-
|
|
28222
|
-
|
|
28223
|
-
|
|
28224
|
-
|
|
29004
|
+
return { message, retryAfterSeconds, status: error.status };
|
|
29005
|
+
}
|
|
29006
|
+
if (error instanceof Error) {
|
|
29007
|
+
const lower = error.message.toLowerCase();
|
|
29008
|
+
if (lower.includes('network')) {
|
|
29009
|
+
return { message: 'Unable to connect to the server. Please check your internet connection.' };
|
|
28225
29010
|
}
|
|
28226
|
-
|
|
28227
|
-
|
|
28228
|
-
const status = state.status;
|
|
28229
|
-
if (status === "displaying" || status === "clicked") {
|
|
28230
|
-
return {
|
|
28231
|
-
...entry,
|
|
28232
|
-
action: { ...entry.action, done: true },
|
|
28233
|
-
};
|
|
28234
|
-
}
|
|
29011
|
+
if (lower.includes('timeout')) {
|
|
29012
|
+
return { message: 'The request timed out. Please try again.' };
|
|
28235
29013
|
}
|
|
28236
|
-
|
|
28237
|
-
|
|
28238
|
-
const status = state.status;
|
|
28239
|
-
if (status === "booked" || status === "cancelled" || status === "error") {
|
|
28240
|
-
return {
|
|
28241
|
-
...entry,
|
|
28242
|
-
action: { ...entry.action, done: true },
|
|
28243
|
-
};
|
|
28244
|
-
}
|
|
29014
|
+
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
29015
|
+
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
28245
29016
|
}
|
|
28246
|
-
|
|
28247
|
-
|
|
28248
|
-
}
|
|
28249
|
-
function hydrateMessages(messages) {
|
|
28250
|
-
return hydrateActionDoneStatus(hydrateActionContent(hydrateToolNames(messages)));
|
|
28251
|
-
}
|
|
28252
|
-
function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
|
|
28253
|
-
// Find all incomplete actions and register resume callbacks
|
|
28254
|
-
for (const message of messages) {
|
|
28255
|
-
if (message.action && !message.action.done) {
|
|
28256
|
-
const toolCallId = message.action.toolCallId;
|
|
28257
|
-
const toolName = message.message.name || message.toolExecuting || "tool";
|
|
28258
|
-
registerActionResumeCallback(toolCallId, async (newState) => {
|
|
28259
|
-
// When user interacts with the action after reload, continue the stream
|
|
28260
|
-
try {
|
|
28261
|
-
// Update the action message with the new state
|
|
28262
|
-
setState(prev => ({
|
|
28263
|
-
...prev,
|
|
28264
|
-
messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
|
|
28265
|
-
? {
|
|
28266
|
-
...m,
|
|
28267
|
-
action: m.action ? { ...m.action, state: newState } : undefined,
|
|
28268
|
-
}
|
|
28269
|
-
: m),
|
|
28270
|
-
isTyping: true,
|
|
28271
|
-
}));
|
|
28272
|
-
const streamState = createStreamState();
|
|
28273
|
-
// Continue the agent stream with the new state
|
|
28274
|
-
for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
|
|
28275
|
-
if (event.type === "done") {
|
|
28276
|
-
finalizeToolMessage(streamState, setState, toolCallId, toolName);
|
|
28277
|
-
streamState.sources = event.sources;
|
|
28278
|
-
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
28279
|
-
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
28280
|
-
continue;
|
|
28281
|
-
}
|
|
28282
|
-
if (event.type === "error") {
|
|
28283
|
-
const errorMessage = {
|
|
28284
|
-
id: generateMessageId(),
|
|
28285
|
-
message: {
|
|
28286
|
-
role: "assistant",
|
|
28287
|
-
content: "Sorry, an error occurred. Please try again later.",
|
|
28288
|
-
},
|
|
28289
|
-
timestamp: new Date().toISOString(),
|
|
28290
|
-
sources: [],
|
|
28291
|
-
isError: true,
|
|
28292
|
-
};
|
|
28293
|
-
upsertMessage(setState, errorMessage, false);
|
|
28294
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
28295
|
-
return;
|
|
28296
|
-
}
|
|
28297
|
-
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
28298
|
-
}
|
|
28299
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
28300
|
-
}
|
|
28301
|
-
catch (error) {
|
|
28302
|
-
console.error("[Action Resume] Failed to continue stream:", error);
|
|
28303
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
28304
|
-
}
|
|
28305
|
-
});
|
|
29017
|
+
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
29018
|
+
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
28306
29019
|
}
|
|
29020
|
+
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
28307
29021
|
}
|
|
29022
|
+
return { message: 'Something went wrong. Please try again.' };
|
|
28308
29023
|
}
|
|
29024
|
+
|
|
28309
29025
|
function createStreamState() {
|
|
28310
29026
|
return {
|
|
28311
29027
|
currentContent: "",
|
|
@@ -28314,6 +29030,7 @@ function createStreamState() {
|
|
|
28314
29030
|
newMessageIds: new Set(),
|
|
28315
29031
|
sources: [],
|
|
28316
29032
|
toolCallToActionId: {},
|
|
29033
|
+
requestId: generateMessageId(),
|
|
28317
29034
|
};
|
|
28318
29035
|
}
|
|
28319
29036
|
function upsertMessage(setState, message, isTyping) {
|
|
@@ -28349,15 +29066,40 @@ function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionI
|
|
|
28349
29066
|
return msg;
|
|
28350
29067
|
}
|
|
28351
29068
|
// Attach suggestions only to the last assistant message
|
|
28352
|
-
|
|
28353
|
-
|
|
28354
|
-
|
|
28355
|
-
return { ...msg, sources, toolCallToActionId };
|
|
29069
|
+
const withSuggestions = index === lastAssistantIndex && suggestions && suggestions.length > 0
|
|
29070
|
+
? { suggestions }
|
|
29071
|
+
: {};
|
|
29072
|
+
return { ...msg, sources, toolCallToActionId, ...withSuggestions };
|
|
28356
29073
|
}),
|
|
28357
29074
|
isTyping: false,
|
|
28358
29075
|
};
|
|
28359
29076
|
});
|
|
28360
29077
|
}
|
|
29078
|
+
function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
|
|
29079
|
+
setState(prev => {
|
|
29080
|
+
const messages = prev.messages.map((entry) => {
|
|
29081
|
+
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
|
|
29082
|
+
if (!matchesToolCall) {
|
|
29083
|
+
return entry;
|
|
29084
|
+
}
|
|
29085
|
+
const existingName = entry.message.name || toolName;
|
|
29086
|
+
return {
|
|
29087
|
+
...entry,
|
|
29088
|
+
message: {
|
|
29089
|
+
role: "tool",
|
|
29090
|
+
content: typeof entry.message.content === "string" ? entry.message.content : "",
|
|
29091
|
+
tool_call_id: toolCallId,
|
|
29092
|
+
name: existingName,
|
|
29093
|
+
},
|
|
29094
|
+
isStreaming: false,
|
|
29095
|
+
toolExecuting: existingName,
|
|
29096
|
+
};
|
|
29097
|
+
});
|
|
29098
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
29099
|
+
});
|
|
29100
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
29101
|
+
}
|
|
29102
|
+
|
|
28361
29103
|
function handleContentEvent(event, streamState, onMessageUpdate, setState) {
|
|
28362
29104
|
streamState.currentContent += event.content;
|
|
28363
29105
|
const assistantMessage = {
|
|
@@ -28404,8 +29146,6 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
|
|
|
28404
29146
|
}
|
|
28405
29147
|
function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
28406
29148
|
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
28407
|
-
// Update state and mark action as done in a single setState call
|
|
28408
|
-
// Keep isTyping: true because the agent may continue generating content after tool completion
|
|
28409
29149
|
setState(prev => {
|
|
28410
29150
|
const messages = prev.messages.map((msg) => {
|
|
28411
29151
|
const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
|
|
@@ -28413,7 +29153,26 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
|
28413
29153
|
return msg;
|
|
28414
29154
|
}
|
|
28415
29155
|
const existingName = msg.message.name || event.tool_name;
|
|
28416
|
-
|
|
29156
|
+
let action = msg.action;
|
|
29157
|
+
if (event.action_id && event.implementation) {
|
|
29158
|
+
action = {
|
|
29159
|
+
implementation: event.implementation,
|
|
29160
|
+
toolCallId: event.tool_call_id,
|
|
29161
|
+
actionId: event.action_id,
|
|
29162
|
+
input: (event.input || {}),
|
|
29163
|
+
state: (event.state || {}),
|
|
29164
|
+
done: event.done,
|
|
29165
|
+
};
|
|
29166
|
+
}
|
|
29167
|
+
else if (action) {
|
|
29168
|
+
action = {
|
|
29169
|
+
...action,
|
|
29170
|
+
input: event.input ? event.input : action.input,
|
|
29171
|
+
state: event.state ? event.state : action.state,
|
|
29172
|
+
done: event.done,
|
|
29173
|
+
};
|
|
29174
|
+
}
|
|
29175
|
+
const updatedMsg = {
|
|
28417
29176
|
...msg,
|
|
28418
29177
|
message: {
|
|
28419
29178
|
role: "tool",
|
|
@@ -28423,14 +29182,10 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
|
28423
29182
|
},
|
|
28424
29183
|
isStreaming: false,
|
|
28425
29184
|
toolExecuting: existingName,
|
|
28426
|
-
action
|
|
28427
|
-
...msg.action,
|
|
28428
|
-
state: event.state || msg.action.state,
|
|
28429
|
-
done: true, // Mark action as completed
|
|
28430
|
-
} : undefined,
|
|
29185
|
+
action,
|
|
28431
29186
|
};
|
|
29187
|
+
return updatedMsg;
|
|
28432
29188
|
});
|
|
28433
|
-
// Keep typing indicator visible - it will be hidden by done/finalizeStreamMessages
|
|
28434
29189
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
28435
29190
|
});
|
|
28436
29191
|
}
|
|
@@ -28462,34 +29217,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
|
|
|
28462
29217
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
28463
29218
|
});
|
|
28464
29219
|
}
|
|
28465
|
-
function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
|
|
28466
|
-
setState(prev => {
|
|
28467
|
-
const messages = prev.messages.map((entry) => {
|
|
28468
|
-
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
|
|
28469
|
-
if (!matchesToolCall) {
|
|
28470
|
-
return entry;
|
|
28471
|
-
}
|
|
28472
|
-
const existingName = entry.message.name || toolName;
|
|
28473
|
-
return {
|
|
28474
|
-
...entry,
|
|
28475
|
-
message: {
|
|
28476
|
-
role: "tool",
|
|
28477
|
-
content: typeof entry.message.content === "string" ? entry.message.content : "",
|
|
28478
|
-
tool_call_id: toolCallId,
|
|
28479
|
-
name: existingName,
|
|
28480
|
-
},
|
|
28481
|
-
isStreaming: false,
|
|
28482
|
-
toolExecuting: existingName,
|
|
28483
|
-
action: entry.action ? {
|
|
28484
|
-
...entry.action,
|
|
28485
|
-
done: true, // Mark action as completed
|
|
28486
|
-
} : undefined,
|
|
28487
|
-
};
|
|
28488
|
-
});
|
|
28489
|
-
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
28490
|
-
});
|
|
28491
|
-
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
28492
|
-
}
|
|
28493
29220
|
function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
|
|
28494
29221
|
streamState.sources = event.sources;
|
|
28495
29222
|
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
@@ -28548,6 +29275,7 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
|
|
|
28548
29275
|
console.warn('[Chat] Unknown event type:', event.type);
|
|
28549
29276
|
}
|
|
28550
29277
|
}
|
|
29278
|
+
|
|
28551
29279
|
async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
|
|
28552
29280
|
let pendingEvent = initialEvent;
|
|
28553
29281
|
while (pendingEvent) {
|
|
@@ -28574,7 +29302,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28574
29302
|
actionId: pendingEvent.action_id,
|
|
28575
29303
|
input: pendingEvent.input,
|
|
28576
29304
|
state: pendingEvent.state,
|
|
28577
|
-
done: false,
|
|
29305
|
+
done: pendingEvent.done ?? false,
|
|
28578
29306
|
},
|
|
28579
29307
|
};
|
|
28580
29308
|
if (streamState.activeToolCallCount === 0) {
|
|
@@ -28588,7 +29316,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28588
29316
|
id: generateMessageId(),
|
|
28589
29317
|
message: {
|
|
28590
29318
|
role: "assistant",
|
|
28591
|
-
content: "Sorry, an error occurred.
|
|
29319
|
+
content: "Sorry, an error occurred.",
|
|
28592
29320
|
},
|
|
28593
29321
|
timestamp: new Date().toISOString(),
|
|
28594
29322
|
sources: [],
|
|
@@ -28612,7 +29340,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28612
29340
|
console.error("[Widget] Frontend action failed:", error);
|
|
28613
29341
|
const errorMessageEntry = {
|
|
28614
29342
|
id: generateMessageId(),
|
|
28615
|
-
message: { role: "assistant", content: "Sorry, an error occurred.
|
|
29343
|
+
message: { role: "assistant", content: "Sorry, an error occurred." },
|
|
28616
29344
|
timestamp: new Date().toISOString(),
|
|
28617
29345
|
sources: [],
|
|
28618
29346
|
isError: true,
|
|
@@ -28624,12 +29352,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28624
29352
|
pendingEvent = null;
|
|
28625
29353
|
const updatedToolMessage = {
|
|
28626
29354
|
...toolMessage,
|
|
28627
|
-
action: toolMessage.action
|
|
28628
|
-
? {
|
|
28629
|
-
...toolMessage.action,
|
|
28630
|
-
state: nextState,
|
|
28631
|
-
}
|
|
28632
|
-
: undefined,
|
|
29355
|
+
action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
|
|
28633
29356
|
};
|
|
28634
29357
|
upsertMessage(setState, updatedToolMessage, true);
|
|
28635
29358
|
let streamEnded = false;
|
|
@@ -28639,22 +29362,20 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28639
29362
|
break;
|
|
28640
29363
|
}
|
|
28641
29364
|
if (event.type === "done") {
|
|
28642
|
-
//
|
|
28643
|
-
// updated by tool_end event or by the user's frontend action.
|
|
29365
|
+
// Finalize tool message and stream messages
|
|
28644
29366
|
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
28645
|
-
// Handle the done event but skip the tool finalization part since we already did it
|
|
28646
29367
|
streamState.sources = event.sources;
|
|
28647
29368
|
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
28648
29369
|
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
28649
29370
|
streamEnded = true;
|
|
28650
|
-
continue;
|
|
29371
|
+
continue;
|
|
28651
29372
|
}
|
|
28652
29373
|
if (event.type === "error") {
|
|
28653
29374
|
const errorMessage = {
|
|
28654
29375
|
id: generateMessageId(),
|
|
28655
29376
|
message: {
|
|
28656
29377
|
role: "assistant",
|
|
28657
|
-
content: "Sorry, an error occurred.
|
|
29378
|
+
content: "Sorry, an error occurred.",
|
|
28658
29379
|
},
|
|
28659
29380
|
timestamp: new Date().toISOString(),
|
|
28660
29381
|
sources: [],
|
|
@@ -28665,73 +29386,79 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28665
29386
|
}
|
|
28666
29387
|
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
28667
29388
|
}
|
|
28668
|
-
// If stream ended without a done event
|
|
29389
|
+
// If stream ended without a done event, finalize the tool message
|
|
28669
29390
|
if (!streamEnded && !pendingEvent) {
|
|
28670
29391
|
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
28671
29392
|
}
|
|
28672
29393
|
}
|
|
28673
29394
|
}
|
|
28674
|
-
function
|
|
28675
|
-
|
|
28676
|
-
|
|
28677
|
-
|
|
28678
|
-
|
|
28679
|
-
|
|
28680
|
-
|
|
28681
|
-
|
|
28682
|
-
|
|
28683
|
-
|
|
28684
|
-
|
|
28685
|
-
|
|
28686
|
-
|
|
28687
|
-
|
|
28688
|
-
|
|
28689
|
-
|
|
28690
|
-
|
|
28691
|
-
|
|
28692
|
-
|
|
28693
|
-
|
|
28694
|
-
|
|
28695
|
-
|
|
28696
|
-
|
|
28697
|
-
|
|
28698
|
-
|
|
28699
|
-
|
|
28700
|
-
|
|
28701
|
-
|
|
28702
|
-
|
|
28703
|
-
|
|
28704
|
-
|
|
28705
|
-
|
|
28706
|
-
|
|
28707
|
-
|
|
28708
|
-
|
|
28709
|
-
|
|
29395
|
+
function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate, createStreamState, registerCallback) {
|
|
29396
|
+
// Find all incomplete actions and register resume callbacks
|
|
29397
|
+
for (const message of messages) {
|
|
29398
|
+
if (message.action && !message.action.done) {
|
|
29399
|
+
const toolCallId = message.action.toolCallId;
|
|
29400
|
+
const toolName = message.message.name || message.toolExecuting || "tool";
|
|
29401
|
+
registerCallback(toolCallId, async (newState) => {
|
|
29402
|
+
// When user interacts with the action after reload, continue the stream
|
|
29403
|
+
try {
|
|
29404
|
+
// Update the action message with the new state and check completion
|
|
29405
|
+
setState(prev => ({
|
|
29406
|
+
...prev,
|
|
29407
|
+
messages: prev.messages.map(m => {
|
|
29408
|
+
if (m.action?.toolCallId !== toolCallId) {
|
|
29409
|
+
return m;
|
|
29410
|
+
}
|
|
29411
|
+
if (!m.action) {
|
|
29412
|
+
return m;
|
|
29413
|
+
}
|
|
29414
|
+
return { ...m, action: { ...m.action, state: newState } };
|
|
29415
|
+
}),
|
|
29416
|
+
isTyping: true,
|
|
29417
|
+
}));
|
|
29418
|
+
const streamState = createStreamState();
|
|
29419
|
+
// Continue the agent stream with the new state
|
|
29420
|
+
for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
|
|
29421
|
+
if (event.type === "done") {
|
|
29422
|
+
finalizeToolMessage(streamState, setState, toolCallId, toolName);
|
|
29423
|
+
streamState.sources = event.sources;
|
|
29424
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
29425
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
29426
|
+
continue;
|
|
29427
|
+
}
|
|
29428
|
+
if (event.type === "error") {
|
|
29429
|
+
const errorMessage = {
|
|
29430
|
+
id: generateMessageId(),
|
|
29431
|
+
message: {
|
|
29432
|
+
role: "assistant",
|
|
29433
|
+
content: "Sorry, an error occurred. Please try again later.",
|
|
29434
|
+
},
|
|
29435
|
+
timestamp: new Date().toISOString(),
|
|
29436
|
+
sources: [],
|
|
29437
|
+
isError: true,
|
|
29438
|
+
};
|
|
29439
|
+
upsertMessage(setState, errorMessage, false);
|
|
29440
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
29441
|
+
return;
|
|
29442
|
+
}
|
|
29443
|
+
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
29444
|
+
}
|
|
29445
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
28710
29446
|
}
|
|
28711
|
-
|
|
28712
|
-
|
|
29447
|
+
catch (error) {
|
|
29448
|
+
console.error("[Action Resume] Failed to continue stream:", error);
|
|
29449
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
28713
29450
|
}
|
|
29451
|
+
});
|
|
28714
29452
|
}
|
|
28715
|
-
return { message, retryAfterSeconds, status: error.status };
|
|
28716
|
-
}
|
|
28717
|
-
if (error instanceof Error) {
|
|
28718
|
-
const lower = error.message.toLowerCase();
|
|
28719
|
-
if (lower.includes('network')) {
|
|
28720
|
-
return { message: 'Unable to connect to the server. Please check your internet connection.' };
|
|
28721
|
-
}
|
|
28722
|
-
if (lower.includes('timeout')) {
|
|
28723
|
-
return { message: 'The request timed out. Please try again.' };
|
|
28724
|
-
}
|
|
28725
|
-
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
28726
|
-
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
28727
|
-
}
|
|
28728
|
-
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
28729
|
-
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
28730
|
-
}
|
|
28731
|
-
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
28732
29453
|
}
|
|
28733
|
-
return { message: 'Something went wrong. Please try again.' };
|
|
28734
29454
|
}
|
|
29455
|
+
|
|
29456
|
+
/**
|
|
29457
|
+
* useChat Hook
|
|
29458
|
+
* Main state management for chat functionality
|
|
29459
|
+
*/
|
|
29460
|
+
// Initialize action handlers immediately to prevent tree-shaking
|
|
29461
|
+
initializeActionHandlers();
|
|
28735
29462
|
function useChat(options) {
|
|
28736
29463
|
const { widgetId, apiUrl, currentRoute, onMessage, onError, skipInitialization = false, } = options;
|
|
28737
29464
|
const [state, setState] = useState({
|
|
@@ -28740,27 +29467,24 @@ function useChat(options) {
|
|
|
28740
29467
|
isLoading: false,
|
|
28741
29468
|
isTyping: false,
|
|
28742
29469
|
error: null,
|
|
28743
|
-
conversationId: '',
|
|
29470
|
+
conversationId: '',
|
|
28744
29471
|
config: null,
|
|
28745
29472
|
});
|
|
28746
29473
|
const stateRef = useRef(state);
|
|
28747
29474
|
useEffect(() => {
|
|
28748
29475
|
stateRef.current = state;
|
|
28749
29476
|
}, [state]);
|
|
28750
|
-
// Chat history state
|
|
28751
29477
|
const [conversations, setConversations] = useState([]);
|
|
28752
|
-
// Stream cancellation and rate limiting
|
|
28753
29478
|
const abortControllerRef = useRef(null);
|
|
29479
|
+
const currentRequestIdRef = useRef(null);
|
|
28754
29480
|
const lastNewChatTimeRef = useRef(0);
|
|
28755
|
-
const NEW_CHAT_COOLDOWN_MS = 5000;
|
|
29481
|
+
const NEW_CHAT_COOLDOWN_MS = 5000;
|
|
28756
29482
|
const apiClient = useRef(new WidgetApiClient({ widgetId, apiUrl, currentRoute }));
|
|
28757
|
-
// Update API client when currentRoute changes
|
|
28758
29483
|
useEffect(() => {
|
|
28759
29484
|
apiClient.current = new WidgetApiClient({ widgetId, apiUrl, currentRoute });
|
|
28760
29485
|
}, [widgetId, apiUrl, currentRoute]);
|
|
28761
29486
|
// Load configuration on mount and hydrate with existing conversation if available
|
|
28762
29487
|
useEffect(() => {
|
|
28763
|
-
// Skip initialization in preview mode
|
|
28764
29488
|
if (skipInitialization) {
|
|
28765
29489
|
return;
|
|
28766
29490
|
}
|
|
@@ -28797,7 +29521,7 @@ function useChat(options) {
|
|
|
28797
29521
|
}));
|
|
28798
29522
|
// Setup resume callbacks for incomplete actions
|
|
28799
29523
|
if (conversationId) {
|
|
28800
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
|
|
29524
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
28801
29525
|
}
|
|
28802
29526
|
}
|
|
28803
29527
|
catch (error) {
|
|
@@ -28814,7 +29538,6 @@ function useChat(options) {
|
|
|
28814
29538
|
initialize();
|
|
28815
29539
|
return () => {
|
|
28816
29540
|
isMounted = false;
|
|
28817
|
-
// Cleanup resume callbacks
|
|
28818
29541
|
state.messages.forEach(message => {
|
|
28819
29542
|
if (message.action?.toolCallId) {
|
|
28820
29543
|
unregisterActionResumeCallback(message.action.toolCallId);
|
|
@@ -28837,19 +29560,15 @@ function useChat(options) {
|
|
|
28837
29560
|
const hasFiles = !!files && files.length > 0;
|
|
28838
29561
|
if (!trimmedContent && !hasFiles)
|
|
28839
29562
|
return;
|
|
28840
|
-
// Block parallel streams - don't allow sending while already streaming
|
|
28841
29563
|
if (stateRef.current.isTyping) {
|
|
28842
29564
|
console.warn('[Widget] Cannot send message while streaming is in progress');
|
|
28843
29565
|
return;
|
|
28844
29566
|
}
|
|
28845
|
-
// Cancel any existing stream before starting new one
|
|
28846
29567
|
if (abortControllerRef.current) {
|
|
28847
29568
|
abortControllerRef.current.abort();
|
|
28848
29569
|
abortControllerRef.current = null;
|
|
28849
29570
|
}
|
|
28850
|
-
// Create new abort controller for this stream
|
|
28851
29571
|
abortControllerRef.current = new AbortController();
|
|
28852
|
-
// Strip [EXECUTE_ACTION:...] prefix from displayed message (but keep for API)
|
|
28853
29572
|
const displayContent = trimmedContent.replace(/^\[EXECUTE_ACTION:[^\]]+\]\s*/, '');
|
|
28854
29573
|
const userMessage = {
|
|
28855
29574
|
id: generateMessageId(),
|
|
@@ -28860,12 +29579,11 @@ function useChat(options) {
|
|
|
28860
29579
|
timestamp: new Date().toISOString(),
|
|
28861
29580
|
sources: [],
|
|
28862
29581
|
};
|
|
28863
|
-
// Add user message immediately
|
|
28864
29582
|
setState(prev => ({
|
|
28865
29583
|
...prev,
|
|
28866
29584
|
messages: [...prev.messages, userMessage],
|
|
28867
|
-
isLoading: false,
|
|
28868
|
-
isTyping: true,
|
|
29585
|
+
isLoading: false,
|
|
29586
|
+
isTyping: true,
|
|
28869
29587
|
error: null,
|
|
28870
29588
|
}));
|
|
28871
29589
|
onMessage?.(userMessage);
|
|
@@ -28905,26 +29623,27 @@ function useChat(options) {
|
|
|
28905
29623
|
}
|
|
28906
29624
|
catch (uploadError) {
|
|
28907
29625
|
console.error('Failed to upload file:', uploadError);
|
|
28908
|
-
// Continue with other files
|
|
28909
29626
|
}
|
|
28910
29627
|
}
|
|
28911
29628
|
}
|
|
28912
|
-
// Stream the response
|
|
28913
29629
|
let lastStreamedMessage = null;
|
|
28914
29630
|
const streamState = createStreamState();
|
|
28915
|
-
|
|
29631
|
+
currentRequestIdRef.current = streamState.requestId;
|
|
28916
29632
|
const currentAbortController = abortControllerRef.current;
|
|
28917
29633
|
const streamConversationId = conversationId;
|
|
28918
|
-
const
|
|
29634
|
+
const streamRequestId = streamState.requestId;
|
|
29635
|
+
const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds, currentAbortController?.signal);
|
|
28919
29636
|
for await (const event of stream) {
|
|
28920
|
-
|
|
28921
|
-
|
|
28922
|
-
|
|
29637
|
+
if (currentAbortController?.signal.aborted ||
|
|
29638
|
+
stateRef.current.conversationId !== streamConversationId ||
|
|
29639
|
+
currentRequestIdRef.current !== streamRequestId) {
|
|
29640
|
+
console.log('[Widget] Stream aborted, conversation changed, or superseded by new request');
|
|
28923
29641
|
break;
|
|
28924
29642
|
}
|
|
28925
29643
|
if (event.type === "action_request") {
|
|
28926
|
-
|
|
28927
|
-
|
|
29644
|
+
if (currentAbortController?.signal.aborted ||
|
|
29645
|
+
stateRef.current.conversationId !== streamConversationId ||
|
|
29646
|
+
currentRequestIdRef.current !== streamRequestId) {
|
|
28928
29647
|
break;
|
|
28929
29648
|
}
|
|
28930
29649
|
await handleActionLoop(apiClient.current, event, streamState, (message) => {
|
|
@@ -28936,30 +29655,26 @@ function useChat(options) {
|
|
|
28936
29655
|
lastStreamedMessage = message;
|
|
28937
29656
|
}, setState);
|
|
28938
29657
|
}
|
|
28939
|
-
|
|
28940
|
-
|
|
28941
|
-
|
|
29658
|
+
if (currentAbortController?.signal.aborted ||
|
|
29659
|
+
stateRef.current.conversationId !== streamConversationId ||
|
|
29660
|
+
currentRequestIdRef.current !== streamRequestId) {
|
|
29661
|
+
console.log('[Widget] Stream was aborted or superseded, skipping finalization');
|
|
28942
29662
|
return;
|
|
28943
29663
|
}
|
|
28944
|
-
// Stream completed - finalize state
|
|
28945
29664
|
setState(prev => ({
|
|
28946
29665
|
...prev,
|
|
28947
29666
|
isLoading: false,
|
|
28948
29667
|
isTyping: false,
|
|
28949
29668
|
}));
|
|
28950
|
-
// Notify about final message
|
|
28951
29669
|
if (lastStreamedMessage) {
|
|
28952
29670
|
onMessage?.(lastStreamedMessage);
|
|
28953
29671
|
}
|
|
28954
|
-
// Generate follow-up suggestions asynchronously
|
|
28955
29672
|
const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
|
|
28956
29673
|
const actionIds = state.config?.actions || [];
|
|
28957
29674
|
if (enableFollowUps) {
|
|
28958
|
-
// Don't await - let it run in background
|
|
28959
29675
|
apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
|
|
28960
29676
|
.then(suggestions => {
|
|
28961
29677
|
if (suggestions.length > 0) {
|
|
28962
|
-
// Attach suggestions to the last assistant message
|
|
28963
29678
|
setState(prev => {
|
|
28964
29679
|
const messages = [...prev.messages];
|
|
28965
29680
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -28988,7 +29703,7 @@ function useChat(options) {
|
|
|
28988
29703
|
},
|
|
28989
29704
|
timestamp: new Date().toISOString(),
|
|
28990
29705
|
sources: [],
|
|
28991
|
-
isError: !fallbackMessage,
|
|
29706
|
+
isError: !fallbackMessage,
|
|
28992
29707
|
};
|
|
28993
29708
|
setState(prev => ({
|
|
28994
29709
|
...prev,
|
|
@@ -29000,9 +29715,6 @@ function useChat(options) {
|
|
|
29000
29715
|
onError?.(err);
|
|
29001
29716
|
}
|
|
29002
29717
|
}, [state.conversationId, state.config, state.messages, onMessage, onError]);
|
|
29003
|
-
/**
|
|
29004
|
-
* Clear all messages
|
|
29005
|
-
*/
|
|
29006
29718
|
const clearMessages = useCallback(() => {
|
|
29007
29719
|
setState(prev => ({
|
|
29008
29720
|
...prev,
|
|
@@ -29015,9 +29727,6 @@ function useChat(options) {
|
|
|
29015
29727
|
clearConversation(widgetId);
|
|
29016
29728
|
}
|
|
29017
29729
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
29018
|
-
/**
|
|
29019
|
-
* Submit feedback for a message
|
|
29020
|
-
*/
|
|
29021
29730
|
const submitFeedback = useCallback(async (messageId, feedback) => {
|
|
29022
29731
|
try {
|
|
29023
29732
|
const message = state.messages.find(msg => msg.id === messageId);
|
|
@@ -29027,7 +29736,6 @@ function useChat(options) {
|
|
|
29027
29736
|
: undefined;
|
|
29028
29737
|
console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
|
|
29029
29738
|
await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
|
|
29030
|
-
// Update message with feedback
|
|
29031
29739
|
setState(prev => ({
|
|
29032
29740
|
...prev,
|
|
29033
29741
|
messages: prev.messages.map(msg => msg.id === messageId
|
|
@@ -29042,9 +29750,6 @@ function useChat(options) {
|
|
|
29042
29750
|
onError?.(err);
|
|
29043
29751
|
}
|
|
29044
29752
|
}, [state.conversationId, onError]);
|
|
29045
|
-
/**
|
|
29046
|
-
* Load conversation history list from localStorage
|
|
29047
|
-
*/
|
|
29048
29753
|
const loadConversations = useCallback(() => {
|
|
29049
29754
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
29050
29755
|
if (!persistConversation || !isStorageAvailable()) {
|
|
@@ -29061,13 +29766,11 @@ function useChat(options) {
|
|
|
29061
29766
|
})));
|
|
29062
29767
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
29063
29768
|
const switchConversation = useCallback(async (conversationId) => {
|
|
29064
|
-
// Cancel any active stream before switching conversations
|
|
29065
29769
|
if (abortControllerRef.current) {
|
|
29066
29770
|
abortControllerRef.current.abort();
|
|
29067
29771
|
abortControllerRef.current = null;
|
|
29068
29772
|
}
|
|
29069
29773
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
29070
|
-
// First try to load from localStorage
|
|
29071
29774
|
if (persistConversation && isStorageAvailable()) {
|
|
29072
29775
|
const stored = loadConversationById(widgetId, conversationId);
|
|
29073
29776
|
if (stored) {
|
|
@@ -29086,7 +29789,6 @@ function useChat(options) {
|
|
|
29086
29789
|
try {
|
|
29087
29790
|
const conversation = await apiClient.current.getOrCreateConversation(conversationId);
|
|
29088
29791
|
const hydratedMessages = hydrateMessages(conversation.messages);
|
|
29089
|
-
// Clear old resume callbacks
|
|
29090
29792
|
state.messages.forEach(message => {
|
|
29091
29793
|
if (message.action?.toolCallId) {
|
|
29092
29794
|
unregisterActionResumeCallback(message.action.toolCallId);
|
|
@@ -29098,9 +29800,7 @@ function useChat(options) {
|
|
|
29098
29800
|
messages: hydratedMessages,
|
|
29099
29801
|
isLoading: false,
|
|
29100
29802
|
}));
|
|
29101
|
-
|
|
29102
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
|
|
29103
|
-
// Save to local storage
|
|
29803
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
29104
29804
|
if (persistConversation && isStorageAvailable()) {
|
|
29105
29805
|
saveConversation(widgetId, conversation.id, hydratedMessages);
|
|
29106
29806
|
}
|
|
@@ -29111,19 +29811,16 @@ function useChat(options) {
|
|
|
29111
29811
|
}
|
|
29112
29812
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
29113
29813
|
const startNewConversation = useCallback(() => {
|
|
29114
|
-
// Rate limiting - prevent spamming new chats
|
|
29115
29814
|
const now = Date.now();
|
|
29116
29815
|
if (now - lastNewChatTimeRef.current < NEW_CHAT_COOLDOWN_MS) {
|
|
29117
29816
|
console.warn('[Widget] New chat rate limited - please wait');
|
|
29118
29817
|
return;
|
|
29119
29818
|
}
|
|
29120
29819
|
lastNewChatTimeRef.current = now;
|
|
29121
|
-
// Cancel any active stream before starting new conversation
|
|
29122
29820
|
if (abortControllerRef.current) {
|
|
29123
29821
|
abortControllerRef.current.abort();
|
|
29124
29822
|
abortControllerRef.current = null;
|
|
29125
29823
|
}
|
|
29126
|
-
// Reset typing state if stream was active
|
|
29127
29824
|
setState(prev => ({
|
|
29128
29825
|
...prev,
|
|
29129
29826
|
messages: [],
|
|
@@ -29142,11 +29839,8 @@ function useChat(options) {
|
|
|
29142
29839
|
if (!persistConversation || !isStorageAvailable()) {
|
|
29143
29840
|
return;
|
|
29144
29841
|
}
|
|
29145
|
-
// Delete from storage
|
|
29146
29842
|
deleteConversation(widgetId, conversationId);
|
|
29147
|
-
// Update local state
|
|
29148
29843
|
setConversations(prev => prev.filter(c => c.id !== conversationId));
|
|
29149
|
-
// If we deleted the current conversation, clear it
|
|
29150
29844
|
if (state.conversationId === conversationId) {
|
|
29151
29845
|
setState(prev => ({
|
|
29152
29846
|
...prev,
|
|
@@ -29166,7 +29860,6 @@ function useChat(options) {
|
|
|
29166
29860
|
sendMessage,
|
|
29167
29861
|
clearMessages,
|
|
29168
29862
|
submitFeedback,
|
|
29169
|
-
// Chat history features
|
|
29170
29863
|
conversations,
|
|
29171
29864
|
loadConversations,
|
|
29172
29865
|
switchConversation,
|
|
@@ -29175,11 +29868,20 @@ function useChat(options) {
|
|
|
29175
29868
|
};
|
|
29176
29869
|
}
|
|
29177
29870
|
|
|
29871
|
+
const ShieldIcon = () => (jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" }), jsx("path", { d: "M9 12l2 2 4-4" })] }));
|
|
29872
|
+
const DataPolicyView = ({ config, widgetName, }) => {
|
|
29873
|
+
const headerTitle = widgetName || config?.appearance?.headerTitle || 'AI Assistant';
|
|
29874
|
+
const hasFileUpload = config?.settings?.enableFileUpload ?? false;
|
|
29875
|
+
const persistsConversation = config?.settings?.persistConversation ?? true;
|
|
29876
|
+
return (jsx("div", { className: "ai-chat-data-policy-view", children: jsxs("div", { className: "ai-chat-data-policy-content", children: [jsxs("div", { className: "ai-chat-data-policy-intro", children: [jsx("div", { className: "ai-chat-data-policy-icon", children: jsx(ShieldIcon, {}) }), jsxs("p", { children: ["Dieser Datenschutzhinweis informiert dich gem\u00E4\u00DF Art. 13 DSGVO dar\u00FCber, wie ", jsx("strong", { children: headerTitle }), " Daten verarbeitet, wenn du diesen Chat nutzt. Bitte beachte, dass der konkrete Umfang der Verarbeitung vom Betreiber dieser Website/Anwendung (dem Verantwortlichen) sowie von den jeweils aktivierten Funktionen abh\u00E4ngt."] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Verantwortlicher / Kontakt" }), jsx("p", { children: "Verantwortlicher im Sinne von Art. 4 Nr. 7 DSGVO ist der Betreiber dieser Website/Anwendung. Die Kontaktdaten (und ggf. die Kontaktdaten eines Datenschutzbeauftragten) findest du in der Datenschutzerkl\u00E4rung bzw. im Impressum der Website, in die dieses Chat-Widget eingebunden ist." })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Verarbeitete Daten (Kategorien)" }), jsxs("ul", { children: [jsxs("li", { children: [jsx("strong", { children: "Chat-Inhalte:" }), " Nachrichten (Text) sowie ggf. Kontextinformationen, die du im Chat angibst. Diese Inhalte werden verarbeitet, um Antworten zu generieren und die Unterhaltung bereitzustellen."] }), hasFileUpload && (jsxs("li", { children: [jsx("strong", { children: "Hochgeladene Dateien:" }), " Dateien, die du an den Chat \u00FCbermittelst, werden zur Bearbeitung des Anliegens verarbeitet. Die Verarbeitung kann das Extrahieren von Text/Informationen umfassen."] })), jsxs("li", { children: [jsx("strong", { children: "Technische Nutzungsdaten:" }), " z.B. Zeitstempel, Sitzungs-/Request-Informationen sowie technische Metadaten, die f\u00FCr den Betrieb, die Sicherheit (Missbrauchspr\u00E4vention) und Fehleranalyse erforderlich sind."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Zwecke und Rechtsgrundlagen" }), jsxs("ul", { children: [jsxs("li", { children: [jsx("strong", { children: "Bereitstellung des Chats und Beantwortung von Anfragen" }), " (Art. 6 Abs. 1 lit. b DSGVO, soweit Vertrags-/vorvertragliche Ma\u00DFnahmen; andernfalls Art. 6 Abs. 1 lit. f DSGVO \u2013 berechtigtes Interesse an effizienter Kommunikation und Support)."] }), jsxs("li", { children: [jsx("strong", { children: "Qualit\u00E4tssicherung, Betrieb und Sicherheit" }), " (Art. 6 Abs. 1 lit. f DSGVO), z.B. zur Stabilit\u00E4t, Missbrauchserkennung und Fehlerbehebung."] }), jsxs("li", { children: [jsx("strong", { children: "Einwilligungsbasierte Verarbeitung" }), " kann erfolgen, sofern der Betreiber dies vorsieht (Art. 6 Abs. 1 lit. a DSGVO)."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Empf\u00E4nger und Auftragsverarbeiter" }), jsxs("ul", { children: [jsxs("li", { children: [jsx("strong", { children: "Hosting/IT-Dienstleister:" }), " Der Betreiber kann Dienstleister f\u00FCr Hosting, Logging, Monitoring und Infrastruktur einsetzen."] }), jsxs("li", { children: [jsx("strong", { children: "KI-Dienstleister:" }), " Zur Generierung von Antworten k\u00F6nnen Chat-Inhalte an KI-Modelle bzw. Anbieter von KI-Infrastruktur \u00FCbertragen werden. Soweit erforderlich, erfolgt dies auf Grundlage eines Auftragsverarbeitungsvertrags (Art. 28 DSGVO)."] }), jsxs("li", { children: [jsx("strong", { children: "Drittlandtransfer:" }), " Falls Empf\u00E4nger au\u00DFerhalb der EU/des EWR sitzen, kann ein Transfer in Drittl\u00E4nder stattfinden. In diesem Fall werden geeignete Garantien (z.B. EU-Standardvertragsklauseln) eingesetzt, soweit erforderlich."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Speicherdauer" }), jsxs("ul", { children: [persistsConversation ? (jsxs("li", { children: [jsx("strong", { children: "Chatverlauf:" }), " Der Chatverlauf kann gespeichert werden, um die Unterhaltung \u00FCber mehrere Sitzungen hinweg fortzusetzen."] })) : (jsxs("li", { children: [jsx("strong", { children: "Chatverlauf:" }), " Der Chatverlauf wird nicht dauerhaft gespeichert und wird beim Schlie\u00DFen des Chats beendet."] })), hasFileUpload && (jsxs("li", { children: [jsx("strong", { children: "Dateien:" }), " Hochgeladene Dateien werden nur so lange verarbeitet, wie dies f\u00FCr die Bearbeitung erforderlich ist, und anschlie\u00DFend gel\u00F6scht, sofern keine l\u00E4ngere Speicherung gesetzlich erforderlich ist."] })), jsxs("li", { children: [jsx("strong", { children: "Technische Protokolle:" }), " Technische Logdaten k\u00F6nnen f\u00FCr einen begrenzten Zeitraum gespeichert werden, um den sicheren Betrieb zu gew\u00E4hrleisten."] })] })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Deine Rechte (Betroffenenrechte)" }), jsxs("ul", { children: [jsxs("li", { children: [jsx("strong", { children: "Auskunft" }), " (Art. 15 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "Berichtigung" }), " (Art. 16 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "L\u00F6schung" }), " (Art. 17 DSGVO) und ", jsx("strong", { children: "Einschr\u00E4nkung der Verarbeitung" }), " (Art. 18 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "Daten\u00FCbertragbarkeit" }), " (Art. 20 DSGVO), soweit anwendbar"] }), jsxs("li", { children: [jsx("strong", { children: "Widerspruch" }), " gegen Verarbeitungen auf Grundlage berechtigter Interessen (Art. 21 DSGVO)"] }), jsxs("li", { children: [jsx("strong", { children: "Beschwerderecht" }), " bei einer Datenschutzaufsichtsbeh\u00F6rde (Art. 77 DSGVO)"] })] }), jsx("p", { children: "Hinweis: Ohne eindeutige Identifikationsmerkmale kann der Betreiber einzelne Chatverl\u00E4ufe ggf. nicht einer Person zuordnen. F\u00FCr Anfragen wende dich bitte an den Betreiber dieser Website/Anwendung." })] }), jsxs("div", { className: "ai-chat-data-policy-section", children: [jsx("h3", { children: "Wichtiger Hinweis" }), jsx("p", { className: "ai-chat-data-policy-warning", children: "Bitte gib keine besonderen Kategorien personenbezogener Daten (z.B. Gesundheitsdaten), Passw\u00F6rter, Kreditkarten-/Bankdaten oder vertrauliche Gesch\u00E4ftsgeheimnisse in den Chat ein. KI-generierte Antworten k\u00F6nnen unzutreffend sein und sollten vor einer Nutzung eigenverantwortlich gepr\u00FCft werden." })] })] }) }));
|
|
29877
|
+
};
|
|
29878
|
+
|
|
29178
29879
|
const MenuIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "4", y1: "10", x2: "20", y2: "10" }), jsx("line", { x1: "10", y1: "14", x2: "20", y2: "14" })] }));
|
|
29179
29880
|
const PlusIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }), jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })] }));
|
|
29180
29881
|
const TrashIcon = () => (jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M3 6h18" }), jsx("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }), jsx("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" })] }));
|
|
29181
29882
|
const CloseIcon = () => (jsxs("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })] }));
|
|
29182
|
-
const
|
|
29883
|
+
const BackIcon = () => (jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M19 12H5" }), jsx("path", { d: "M12 19l-7-7 7-7" })] }));
|
|
29884
|
+
const ChatWindow = ({ messages, isLoading, isTyping, config, onSendMessage, onClose: _onClose, onFeedback, onActionClick,
|
|
29183
29885
|
// Chat history props (only active when persistConversation is true)
|
|
29184
29886
|
conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
|
|
29185
29887
|
// Override props for live preview
|
|
@@ -29196,6 +29898,8 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
|
|
|
29196
29898
|
const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
|
|
29197
29899
|
// Track if history panel is open
|
|
29198
29900
|
const [showHistory, setShowHistory] = useState(false);
|
|
29901
|
+
// Track if data policy view is open
|
|
29902
|
+
const [showDataPolicy, setShowDataPolicy] = useState(false);
|
|
29199
29903
|
// Scroll button state (managed by MessageList)
|
|
29200
29904
|
const [showScrollButton, setShowScrollButton] = useState(false);
|
|
29201
29905
|
const [scrollToBottom, setScrollToBottom] = useState(null);
|
|
@@ -29205,6 +29909,13 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
|
|
|
29205
29909
|
}, []);
|
|
29206
29910
|
// History exit animation when starting a new chat from overview
|
|
29207
29911
|
const [isHistoryExiting, setIsHistoryExiting] = useState(false);
|
|
29912
|
+
// Handle data policy click
|
|
29913
|
+
const handleDataPolicyClick = useCallback(() => {
|
|
29914
|
+
setShowDataPolicy(true);
|
|
29915
|
+
}, []);
|
|
29916
|
+
const handleDataPolicyBack = useCallback(() => {
|
|
29917
|
+
setShowDataPolicy(false);
|
|
29918
|
+
}, []);
|
|
29208
29919
|
// Load conversations when history panel opens
|
|
29209
29920
|
const handleOpenHistory = () => {
|
|
29210
29921
|
setShowHistory(true);
|
|
@@ -29252,10 +29963,22 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
|
|
|
29252
29963
|
// The backend will detect and trigger the action based on the message
|
|
29253
29964
|
onSendMessage(question);
|
|
29254
29965
|
};
|
|
29255
|
-
return (jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''}`, children: showHistory ? (jsxs(Fragment, { children: [jsx("div", { className: "ai-chat-title", children: headerTitle }), jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsx(PlusIcon, {}) })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsx(MenuIcon, {}) })), jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsx(CloseIcon, {}) })] })] })) }),
|
|
29966
|
+
return (jsxs("div", { className: `ai-chat-window size-${size}`, role: "dialog", "aria-label": "Chat window", children: [jsx("div", { className: `ai-chat-header ${showHistory ? 'is-history' : ''} ${showDataPolicy ? 'is-data-policy' : ''}`, children: showDataPolicy ? (jsxs(Fragment, { children: [jsx("button", { className: "ai-chat-header-button", onClick: handleDataPolicyBack, "aria-label": "Back to chat", children: jsx(BackIcon, {}) }), jsx("div", { className: "ai-chat-title", children: "Datenschutzhinweis" })] })) : showHistory ? (jsxs(Fragment, { children: [jsx("div", { className: "ai-chat-title", children: headerTitle }), jsx("button", { className: "ai-chat-header-button", onClick: handleNewConversation, "aria-label": "New chat", children: jsx(PlusIcon, {}) })] })) : (jsxs(Fragment, { children: [jsxs("div", { className: "ai-chat-header-content", children: [appearance?.logo && (jsx("img", { src: appearance.logo, alt: "Logo", className: "ai-chat-logo" })), jsx("div", { className: "ai-chat-title", children: headerTitle })] }), jsxs("div", { className: "ai-chat-header-actions", children: [canShowHistory && (jsx("button", { className: "ai-chat-header-button", onClick: handleOpenHistory, "aria-label": "Chat overview", children: jsx(MenuIcon, {}) })), jsx("button", { className: "ai-chat-close-button header-close-button", onClick: _onClose, "aria-label": "Close chat", children: jsx(CloseIcon, {}) })] })] })) }), showDataPolicy ? (jsx(DataPolicyView, { config: config, onBack: handleDataPolicyBack, widgetName: headerTitle })) : showHistory ? (
|
|
29967
|
+
/* History Panel */
|
|
29968
|
+
jsxs("div", { className: "ai-chat-history-panel", children: [conversations.length === 0 ? (jsx("div", { className: "ai-chat-history-empty", children: "No previous conversations" })) : (jsx("div", { className: `ai-chat-history-list ${isHistoryExiting ? 'exiting' : ''}`, children: conversations.map((conv) => (jsx("div", { className: `ai-chat-history-item ${conv.id === currentConversationId ? 'active' : ''}`, onClick: () => handleSelectConversation(conv.id), children: jsxs("div", { className: "ai-chat-history-item-content", children: [jsx("div", { className: "ai-chat-history-item-preview", children: conv.preview }), onDeleteConversation && (jsx("button", { className: "ai-chat-history-item-delete", onClick: (e) => {
|
|
29256
29969
|
e.stopPropagation();
|
|
29257
29970
|
onDeleteConversation(conv.id);
|
|
29258
|
-
}, "aria-label": "Delete conversation", children: jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload })] })) : (jsxs(Fragment, { children: [
|
|
29971
|
+
}, "aria-label": "Delete conversation", children: jsx(TrashIcon, {}) }))] }) }, conv.id))) })), jsx(MessageInput, { onSend: (text) => handleSendFromOverview(text), placeholder: inputPlaceholder, disabled: isLoading, enableFileUpload: settings?.enableFileUpload, showDataPolicy: settings?.showDataPolicy ?? true, onDataPolicyClick: handleDataPolicyClick })] })) : (jsxs(Fragment, { children: [maxMessages && userMessageCount >= maxMessages - 2 && !isLimitReached && (jsxs("div", { className: "ai-chat-warning", role: "alert", children: [maxMessages - userMessageCount, " message", maxMessages - userMessageCount !== 1 ? 's' : '', " remaining"] })), isLimitReached && (jsx("div", { className: "ai-chat-error", role: "alert", children: "Message limit reached. Please start a new conversation." })), (() => {
|
|
29972
|
+
console.log('[DEBUG ChatWindow] Rendering MessageList with', messages.length, 'messages');
|
|
29973
|
+
messages.forEach((m, i) => {
|
|
29974
|
+
console.log(`[DEBUG ChatWindow] msg ${i}:`, { role: m.message.role, hasAction: !!m.action, impl: m.action?.implementation });
|
|
29975
|
+
});
|
|
29976
|
+
console.log('[DEBUG ChatWindow] getActionRenderer available:', !!getActionRenderer);
|
|
29977
|
+
if (getActionRenderer) {
|
|
29978
|
+
console.log('[DEBUG ChatWindow] Testing renderer for query-contact-directory:', !!getActionRenderer('query-contact-directory'));
|
|
29979
|
+
}
|
|
29980
|
+
return null;
|
|
29981
|
+
})(), 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, onFeedback: onFeedback, onScrollStateChange: handleScrollStateChange, getActionRenderer: getActionRenderer }), jsx(ScrollButton, { onClick: () => scrollToBottom?.(), visible: showScrollButton }), 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 })] }))] }));
|
|
29259
29982
|
};
|
|
29260
29983
|
|
|
29261
29984
|
/**
|
|
@@ -29661,7 +30384,7 @@ function styleInject(css, ref) {
|
|
|
29661
30384
|
if ( ref === void 0 ) ref = {};
|
|
29662
30385
|
var insertAt = ref.insertAt;
|
|
29663
30386
|
|
|
29664
|
-
if (typeof document === 'undefined') { return; }
|
|
30387
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
29665
30388
|
|
|
29666
30389
|
var head = document.head || document.getElementsByTagName('head')[0];
|
|
29667
30390
|
var style = document.createElement('style');
|
|
@@ -29684,7 +30407,10 @@ function styleInject(css, ref) {
|
|
|
29684
30407
|
}
|
|
29685
30408
|
}
|
|
29686
30409
|
|
|
29687
|
-
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%}";
|
|
30410
|
+
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: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-welcome-bubble{animation:ai-chat-bubble-fade-in .3s ease-out;background:var(--button-color,var(--btn-primary-bg,#07f));border:none;border-radius:12px;box-shadow:0 4px 12px rgba(0,0,0,.15);color:var(--button-icon-color,var(--btn-primary-text,#fff));cursor:pointer;font-size:14px;font-weight:500;line-height:1.4;padding:12px 16px;position:absolute;width:200px;z-index:0}.ai-chat-widget-container.bottom-right .ai-chat-welcome-bubble{bottom:68px;right:0;text-align:right}.ai-chat-widget-container.bottom-left .ai-chat-welcome-bubble{bottom:68px;left:0;right:auto;text-align:left}.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{right:0;text-align:right;top:68px}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble{left:0;right:auto;text-align:left;top:68px}.ai-chat-welcome-bubble:hover{filter:brightness(1.1)}@keyframes ai-chat-bubble-fade-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}.ai-chat-widget-container.top-left .ai-chat-welcome-bubble,.ai-chat-widget-container.top-right .ai-chat-welcome-bubble{animation-name:ai-chat-bubble-fade-in-down}@keyframes ai-chat-bubble-fade-in-down{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.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-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 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-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-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{border-top:1px solid var(--border-subtle,rgba(0,0,0,.08));color:var(--text-muted,#71717a);font-size:12px;font-style:italic;margin-top:4px;padding-top:8px}.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;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}.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)}}";
|
|
30411
|
+
styleInject(css_248z$1);
|
|
30412
|
+
|
|
30413
|
+
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{align-items:center;background:var(--bg-subtle,rgba(0,0,0,.02));border-radius:12px;display:flex;flex-direction:column;margin-bottom:20px;padding:16px;text-align:center}.ai-chat-widget.dark .ai-chat-data-policy-intro{background:var(--bg-subtle,hsla(0,0%,100%,.04))}.ai-chat-data-policy-icon{align-items:center;background:var(--primary-color,#07f);border-radius:12px;color:#fff;display:flex;height:48px;justify-content:center;margin-bottom:12px;width:48px}.ai-chat-data-policy-intro p{color:var(--text-secondary,#52525b);font-size:13px;line-height:1.5;margin:0}.ai-chat-widget.dark .ai-chat-data-policy-intro p{color:var(--text-secondary,#a1a1aa)}.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:13px;font-weight:600;letter-spacing:.02em;margin:0 0 8px;text-transform:uppercase}.ai-chat-widget.dark .ai-chat-data-policy-section h3{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section ul{list-style:none;margin:0;padding:0}.ai-chat-data-policy-section li{color:var(--text-secondary,#52525b);font-size:12px;line-height:1.5;padding:8px 0 8px 16px;position:relative}.ai-chat-widget.dark .ai-chat-data-policy-section li{color:var(--text-secondary,#a1a1aa)}.ai-chat-data-policy-section li:before{background:var(--text-muted,#a1a1aa);border-radius:50%;content:\"\";height:4px;left:0;position:absolute;top:14px;width:4px}.ai-chat-data-policy-section li strong{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-data-policy-section li strong{color:var(--text-primary,#fafafa)}.ai-chat-data-policy-section p{color:var(--text-secondary,#52525b);font-size:12px;line-height:1.5;margin:0}.ai-chat-widget.dark .ai-chat-data-policy-section p{color:var(--text-secondary,#a1a1aa)}.ai-chat-data-policy-warning{background:rgba(234,179,8,.1);border:1px solid rgba(234,179,8,.3);border-radius:8px;color:#92400e!important;padding:12px}.ai-chat-widget.dark .ai-chat-data-policy-warning{background:rgba(234,179,8,.15);border-color:rgba(234,179,8,.25);color:#fbbf24!important}";
|
|
29688
30414
|
styleInject(css_248z);
|
|
29689
30415
|
|
|
29690
30416
|
// Icon components mapping
|
|
@@ -29692,9 +30418,10 @@ const iconComponents = {
|
|
|
29692
30418
|
FiMessageCircle: () => (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: 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" }) })),
|
|
29693
30419
|
FiChevronDown: () => (jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "6 9 12 15 18 9" }) })),
|
|
29694
30420
|
};
|
|
29695
|
-
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', }) => {
|
|
30421
|
+
const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = false, previewConfig, position = 'bottom-right', primaryColor, size, headerTitle, welcomeTitle, welcomeMessage, placeholder, welcomeBubbleText, theme, suggestedQuestions, customStyles, currentRoute, defaultOpen = false, zIndex, containerMode = false, onOpen, onClose, onMessage, onError, mode = 'bubble', }) => {
|
|
29696
30422
|
const [isOpen, setIsOpen] = useState(defaultOpen);
|
|
29697
30423
|
const [autoDetectedTheme, setAutoDetectedTheme] = useState('light');
|
|
30424
|
+
const [showWelcomeBubble, setShowWelcomeBubble] = useState(false);
|
|
29698
30425
|
const widgetRef = useRef(null);
|
|
29699
30426
|
const containerRef = useRef(null);
|
|
29700
30427
|
// Determine mode
|
|
@@ -29716,6 +30443,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29716
30443
|
showChatHistory: true,
|
|
29717
30444
|
showTimestamps: true,
|
|
29718
30445
|
showTypingIndicator: true,
|
|
30446
|
+
showToolCalls: false,
|
|
29719
30447
|
enableFileUpload: false,
|
|
29720
30448
|
enableFeedback: true,
|
|
29721
30449
|
},
|
|
@@ -29754,7 +30482,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29754
30482
|
const messages = previewMode ? [] : chatHook.messages;
|
|
29755
30483
|
const isLoading = previewMode ? false : chatHook.isLoading;
|
|
29756
30484
|
const isTyping = previewMode ? false : chatHook.isTyping;
|
|
29757
|
-
const error = previewMode ? null : chatHook.error;
|
|
29758
30485
|
const config = previewMode ? mergedPreviewConfig : chatHook.config;
|
|
29759
30486
|
const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
|
|
29760
30487
|
const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
|
|
@@ -29789,8 +30516,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29789
30516
|
mediaQuery.removeEventListener('change', handleMediaChange);
|
|
29790
30517
|
};
|
|
29791
30518
|
}, [config]);
|
|
29792
|
-
//
|
|
30519
|
+
// Check if device is mobile
|
|
30520
|
+
const isMobile = typeof window !== 'undefined' && window.innerWidth <= 480;
|
|
30521
|
+
// Handle auto-open (only for bubble mode, disabled on mobile)
|
|
29793
30522
|
useEffect(() => {
|
|
30523
|
+
// Never auto-open on mobile devices
|
|
30524
|
+
if (isMobile)
|
|
30525
|
+
return undefined;
|
|
29794
30526
|
if (!isEmbedded && config?.settings.autoOpen) {
|
|
29795
30527
|
const delay = config.settings.autoOpenDelay || 0;
|
|
29796
30528
|
const timer = setTimeout(() => {
|
|
@@ -29800,7 +30532,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29800
30532
|
return () => clearTimeout(timer);
|
|
29801
30533
|
}
|
|
29802
30534
|
return undefined;
|
|
29803
|
-
}, [config, onOpen, isEmbedded]);
|
|
30535
|
+
}, [config, onOpen, isEmbedded, isMobile]);
|
|
29804
30536
|
// Handle close on Escape key (only for bubble mode)
|
|
29805
30537
|
useEffect(() => {
|
|
29806
30538
|
if (!isOpen || isEmbedded)
|
|
@@ -29814,6 +30546,37 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29814
30546
|
document.addEventListener('keydown', handleEscapeKey);
|
|
29815
30547
|
return () => document.removeEventListener('keydown', handleEscapeKey);
|
|
29816
30548
|
}, [isOpen, onClose, isEmbedded]);
|
|
30549
|
+
// Handle body scroll lock on mobile when widget is open
|
|
30550
|
+
useEffect(() => {
|
|
30551
|
+
if (!isOpen || isEmbedded)
|
|
30552
|
+
return;
|
|
30553
|
+
// Only apply scroll lock on mobile
|
|
30554
|
+
const checkMobile = window.innerWidth <= 480;
|
|
30555
|
+
if (!checkMobile)
|
|
30556
|
+
return;
|
|
30557
|
+
// Add class to body to lock scrolling
|
|
30558
|
+
document.body.classList.add('ai-chat-widget-open');
|
|
30559
|
+
return () => {
|
|
30560
|
+
document.body.classList.remove('ai-chat-widget-open');
|
|
30561
|
+
};
|
|
30562
|
+
}, [isOpen, isEmbedded]);
|
|
30563
|
+
// Handle welcome bubble visibility per session
|
|
30564
|
+
// Shows on each new session if welcomeBubbleText is configured
|
|
30565
|
+
useEffect(() => {
|
|
30566
|
+
if (isEmbedded || previewMode)
|
|
30567
|
+
return;
|
|
30568
|
+
const bubbleText = welcomeBubbleText ?? config?.appearance?.welcomeBubbleText;
|
|
30569
|
+
if (!bubbleText) {
|
|
30570
|
+
setShowWelcomeBubble(false);
|
|
30571
|
+
return;
|
|
30572
|
+
}
|
|
30573
|
+
// Check if bubble was already dismissed this session
|
|
30574
|
+
const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
|
|
30575
|
+
const wasDismissed = sessionStorage.getItem(storageKey) === 'true';
|
|
30576
|
+
if (!wasDismissed && !isOpen) {
|
|
30577
|
+
setShowWelcomeBubble(true);
|
|
30578
|
+
}
|
|
30579
|
+
}, [widgetId, welcomeBubbleText, config, isOpen, isEmbedded, previewMode]);
|
|
29817
30580
|
// Determine theme - use prop override if provided, otherwise auto-detect
|
|
29818
30581
|
const appearanceConfig = config?.appearance;
|
|
29819
30582
|
const effectiveTheme = theme ?? autoDetectedTheme;
|
|
@@ -29827,6 +30590,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29827
30590
|
const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
|
|
29828
30591
|
const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
|
|
29829
30592
|
const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
|
|
30593
|
+
const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
|
|
29830
30594
|
// Generate styles using simplified theme system
|
|
29831
30595
|
const simpleAppearance = {
|
|
29832
30596
|
accentColor};
|
|
@@ -29848,6 +30612,18 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29848
30612
|
return;
|
|
29849
30613
|
const newState = !isOpen;
|
|
29850
30614
|
setIsOpen(newState);
|
|
30615
|
+
// Dismiss welcome bubble when chat is opened
|
|
30616
|
+
if (newState && showWelcomeBubble) {
|
|
30617
|
+
setShowWelcomeBubble(false);
|
|
30618
|
+
// Store in sessionStorage so it doesn't show again this session
|
|
30619
|
+
const storageKey = `ai-chat-bubble-dismissed-${widgetId || 'default'}`;
|
|
30620
|
+
try {
|
|
30621
|
+
sessionStorage.setItem(storageKey, 'true');
|
|
30622
|
+
}
|
|
30623
|
+
catch {
|
|
30624
|
+
// Ignore storage errors
|
|
30625
|
+
}
|
|
30626
|
+
}
|
|
29851
30627
|
if (newState) {
|
|
29852
30628
|
onOpen?.();
|
|
29853
30629
|
}
|
|
@@ -29878,13 +30654,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29878
30654
|
const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
|
|
29879
30655
|
// Embedded mode renders directly without wrapper positioning
|
|
29880
30656
|
if (isEmbedded) {
|
|
29881
|
-
return (jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping,
|
|
30657
|
+
return (jsx("div", { ref: containerRef, className: `ai-chat-widget ai-chat-widget-embedded ${effectiveTheme}`, style: { ...mergedStyles, width: '100%', height: '100%' }, children: jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: sendMessage, onClose: () => { }, onFeedback: handleFeedback, onActionClick: handleActionClick, conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId, headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions }) }));
|
|
29882
30658
|
}
|
|
29883
|
-
return (jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''}`, children: [isOpen && (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping,
|
|
30659
|
+
return (jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition} ${isOpen ? 'is-open' : ''} ${containerMode ? 'container-mode' : ''}`, children: [isOpen && (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback, onActionClick: handleActionClick,
|
|
29884
30660
|
// Chat history props (only active when persistConversation is true)
|
|
29885
30661
|
conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
|
|
29886
30662
|
// Override props for live preview
|
|
29887
|
-
headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })] }) }));
|
|
30663
|
+
headerTitleOverride: effectiveHeaderTitle, welcomeTitleOverride: effectiveWelcomeTitle, welcomeMessageOverride: effectiveWelcomeMessage, placeholderOverride: effectivePlaceholder, suggestedQuestionsOverride: suggestedQuestions })), !isOpen && effectiveWelcomeBubbleText && (previewMode || showWelcomeBubble) && (jsx("div", { className: "ai-chat-welcome-bubble", onClick: handleToggle, children: jsx("span", { children: effectiveWelcomeBubbleText }) })), jsx("button", { className: `ai-chat-button ${isOpen ? 'is-open' : ''}`, onClick: handleToggle, "aria-label": isOpen ? "Minimize chat" : "Open chat", children: jsx("div", { className: "ai-chat-button-svg", children: jsx(IconComponent, {}) }) })] }) }));
|
|
29888
30664
|
};
|
|
29889
30665
|
|
|
29890
30666
|
export { ApiError, ChatWidget, useChat };
|