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