@chatwidgetai/chat-widget 0.2.9 → 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 +1546 -331
- 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.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1546 -331
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1546 -331
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +10 -3
- 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,17 +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$
|
|
27158
|
-
};
|
|
27159
|
-
|
|
27160
|
-
const Sources = ({ sources, displayMode = 'with-score' }) => {
|
|
27161
|
-
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
27162
|
-
if (!sources || sources.length === 0 || displayMode === 'none')
|
|
27163
|
-
return null;
|
|
27164
|
-
return (jsxRuntime.jsxs("div", { className: "ai-chat-sources", children: [jsxRuntime.jsxs("button", { className: "ai-chat-sources-toggle", onClick: () => setIsExpanded(!isExpanded), "aria-expanded": isExpanded, children: [jsxRuntime.jsx("span", { className: "ai-chat-sources-icon", children: isExpanded ? '▼' : '▶' }), jsxRuntime.jsxs("span", { className: "ai-chat-sources-title", children: [sources.length, " source", sources.length > 1 ? 's' : ''] })] }), isExpanded && displayMode !== 'minimal' && (jsxRuntime.jsx("div", { className: "ai-chat-sources-list", children: sources.map((source, index) => (jsxRuntime.jsxs("div", { className: "ai-chat-source-item", children: [jsxRuntime.jsxs("div", { className: "ai-chat-source-number", children: [index + 1, "."] }), jsxRuntime.jsxs("div", { className: "ai-chat-source-details", children: [displayMode === 'with-score' && source.score && (jsxRuntime.jsxs("div", { className: "ai-chat-source-score", children: ["Score: ", (source.score * 100).toFixed(0), "%"] })), (displayMode === 'with-content' || displayMode === 'full') && source.doc.pageContent && (jsxRuntime.jsxs("div", { className: "ai-chat-source-content", children: [source.doc.pageContent.substring(0, 100), source.doc.pageContent.length > 100 ? '...' : ''] })), displayMode === 'full' && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [source.score && (jsxRuntime.jsxs("div", { className: "ai-chat-source-score", children: ["Score: ", (source.score * 100).toFixed(0), "%"] })), source.doc.metadata && Object.keys(source.doc.metadata).length > 0 && (jsxRuntime.jsx("div", { className: "ai-chat-source-metadata", children: Object.entries(source.doc.metadata).map(([key, value]) => (jsxRuntime.jsxs("span", { className: "ai-chat-source-meta-item", children: [key, ": ", String(value)] }, key))) }))] }))] })] }, `${source.kbId}-${source.doc.id}-${index}`))) }))] }));
|
|
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" })] }))] }));
|
|
27165
27165
|
};
|
|
27166
27166
|
|
|
27167
|
-
const Message = ({ message, showTimestamp = true, enableFeedback = true,
|
|
27167
|
+
const Message = ({ message, showTimestamp = true, enableFeedback = true, onFeedback, }) => {
|
|
27168
27168
|
const formatTime = (timestamp) => {
|
|
27169
27169
|
const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;
|
|
27170
27170
|
return date.toLocaleTimeString('en-US', {
|
|
@@ -27184,15 +27184,15 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
|
|
|
27184
27184
|
return null;
|
|
27185
27185
|
}
|
|
27186
27186
|
// AI message rendering
|
|
27187
|
+
// Note: Actions are rendered by ToolMessageGroup for tool messages, not here
|
|
27187
27188
|
if (isAssistant) {
|
|
27188
27189
|
const aiContent = message.message.content || '';
|
|
27189
27190
|
const hasContent = aiContent.trim().length > 0;
|
|
27190
27191
|
if (!hasContent)
|
|
27191
27192
|
return null;
|
|
27192
|
-
|
|
27193
|
-
|
|
27194
|
-
|
|
27195
|
-
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), showTimestamp && (jsxRuntime.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntime.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] })), showSources && message.sources?.length > 0 && (jsxRuntime.jsx(Sources, { sources: message.sources, displayMode: sourceDisplayMode }))] }));
|
|
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 }))] }))] }));
|
|
27196
27196
|
}
|
|
27197
27197
|
// System message rendering
|
|
27198
27198
|
if (isSystem) {
|
|
@@ -27206,30 +27206,85 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
|
|
|
27206
27206
|
return null;
|
|
27207
27207
|
};
|
|
27208
27208
|
|
|
27209
|
-
|
|
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 }) => {
|
|
27210
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
|
+
});
|
|
27263
|
+
// If tool indicator is hidden AND there are no action cards to render, don't render anything
|
|
27264
|
+
if (!showToolIndicator && actionMessages.length === 0) {
|
|
27265
|
+
return null;
|
|
27266
|
+
}
|
|
27211
27267
|
const badges = messages.map((message) => {
|
|
27212
27268
|
const toolName = message.toolExecuting || message.message.name || 'Tool';
|
|
27213
27269
|
const hasError = message.isError || false;
|
|
27214
|
-
const
|
|
27215
|
-
const actionStatus = actionState?.status;
|
|
27216
|
-
const terminalStatuses = ['completed', 'booked', 'scheduled', 'failed', 'cancelled'];
|
|
27217
|
-
const isTerminalStatus = actionStatus && terminalStatuses.includes(actionStatus);
|
|
27218
|
-
const isDone = message.action ? (message.action.done ?? isTerminalStatus ?? false) : !message.isStreaming;
|
|
27219
|
-
const isLoading = !isDone;
|
|
27270
|
+
const loading = isActionLoading(message);
|
|
27220
27271
|
return {
|
|
27221
27272
|
id: message.id,
|
|
27222
27273
|
name: toolName,
|
|
27223
|
-
status:
|
|
27274
|
+
status: loading ? 'loading' : hasError ? 'error' : 'completed',
|
|
27224
27275
|
};
|
|
27225
27276
|
});
|
|
27226
|
-
return (jsxRuntime.jsxs("div", { className: "ai-chat-message tool", children: [jsxRuntime.jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
|
|
27227
|
-
if (!message.action || !getActionRenderer)
|
|
27277
|
+
return (jsxRuntime.jsxs("div", { className: "ai-chat-message tool", children: [showToolIndicator && jsxRuntime.jsx(ToolIndicator, { badges: badges }), actionMessages.map((message) => {
|
|
27278
|
+
if (!message.action || !getActionRenderer) {
|
|
27279
|
+
console.log('[ToolMessageGroup] Skipping - no action or renderer:', { hasAction: !!message.action, hasGetRenderer: !!getActionRenderer });
|
|
27228
27280
|
return null;
|
|
27281
|
+
}
|
|
27229
27282
|
const renderer = getActionRenderer(message.action.implementation);
|
|
27230
|
-
if (!renderer)
|
|
27283
|
+
if (!renderer) {
|
|
27284
|
+
console.log('[ToolMessageGroup] No renderer for:', message.action.implementation);
|
|
27231
27285
|
return null;
|
|
27232
|
-
|
|
27286
|
+
}
|
|
27287
|
+
return (jsxRuntime.jsx("div", { className: "ai-chat-tool-action", children: renderer(message, accentColor, variant) }, `action-${message.id}`));
|
|
27233
27288
|
})] }));
|
|
27234
27289
|
};
|
|
27235
27290
|
|
|
@@ -27291,12 +27346,16 @@ const FollowUpSuggestions = ({ suggestions, onQuestionClick, onActionClick, acce
|
|
|
27291
27346
|
};
|
|
27292
27347
|
|
|
27293
27348
|
const MessageList = (props) => {
|
|
27294
|
-
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true,
|
|
27349
|
+
const { messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, showToolCalls = false, enableFeedback = true, welcomeTitle, welcomeMessage, suggestedQuestions, accentColor, onSuggestedQuestionClick, onActionClick, onFeedback, onScrollStateChange, getActionRenderer, variant, } = props;
|
|
27295
27350
|
const containerRef = React.useRef(null);
|
|
27296
27351
|
const messagesEndRef = React.useRef(null);
|
|
27297
27352
|
const [showScrollButton, setShowScrollButton] = React.useState(false);
|
|
27298
27353
|
const prevMessageCountRef = React.useRef(0);
|
|
27299
|
-
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]);
|
|
27300
27359
|
const checkScrollPosition = React.useCallback(() => {
|
|
27301
27360
|
const c = containerRef.current;
|
|
27302
27361
|
if (!c)
|
|
@@ -27332,39 +27391,70 @@ const MessageList = (props) => {
|
|
|
27332
27391
|
checkScrollPosition();
|
|
27333
27392
|
}, [messages, isTyping, checkScrollPosition]);
|
|
27334
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
|
+
});
|
|
27335
27405
|
const result = [];
|
|
27336
27406
|
let toolGroup = [];
|
|
27337
|
-
const flush = () => {
|
|
27338
|
-
|
|
27339
|
-
|
|
27340
|
-
|
|
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
|
+
};
|
|
27341
27414
|
for (const m of messages) {
|
|
27342
|
-
if (m.message.role === 'tool')
|
|
27415
|
+
if (m.message.role === 'tool') {
|
|
27416
|
+
console.log('[DEBUG MessageList] Adding to tool group:', m.id);
|
|
27343
27417
|
toolGroup.push(m);
|
|
27418
|
+
}
|
|
27344
27419
|
else if (m.message.role === 'user') {
|
|
27345
27420
|
flush();
|
|
27346
27421
|
result.push({ type: 'message', message: m });
|
|
27347
27422
|
}
|
|
27348
|
-
else if (m.message.role === 'assistant'
|
|
27349
|
-
|
|
27350
|
-
|
|
27423
|
+
else if (m.message.role === 'assistant') {
|
|
27424
|
+
// Include assistant messages if they have content OR are still streaming (content may arrive)
|
|
27425
|
+
const hasContent = (m.message.content || '').trim().length > 0;
|
|
27426
|
+
if (hasContent || m.isStreaming) {
|
|
27427
|
+
flush();
|
|
27428
|
+
result.push({ type: 'message', message: m });
|
|
27429
|
+
}
|
|
27430
|
+
// Don't flush on empty assistant messages - let tools continue grouping
|
|
27351
27431
|
}
|
|
27352
|
-
else
|
|
27432
|
+
else {
|
|
27353
27433
|
flush();
|
|
27354
27434
|
result.push({ type: 'message', message: m });
|
|
27355
27435
|
}
|
|
27356
27436
|
}
|
|
27357
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
|
+
});
|
|
27358
27447
|
return result;
|
|
27359
27448
|
}, [messages]);
|
|
27360
27449
|
const hasSuggestions = messages.length === 0 && onSuggestedQuestionClick && suggestedQuestions?.length;
|
|
27361
27450
|
const showWelcome = welcomeTitle || welcomeMessage || hasSuggestions;
|
|
27362
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) => {
|
|
27363
|
-
if (item.type === 'tool-group')
|
|
27364
|
-
return jsxRuntime.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer }, `tg-${i}`);
|
|
27452
|
+
if (item.type === 'tool-group') {
|
|
27453
|
+
return jsxRuntime.jsx(ToolMessageGroup, { messages: item.messages, getActionRenderer: getActionRenderer, showToolIndicator: showToolCalls, accentColor: accentColor, variant: variant }, `tg-${i}`);
|
|
27454
|
+
}
|
|
27365
27455
|
const isLast = i === groupedMessages.length - 1;
|
|
27366
27456
|
const hasFollowUp = item.message.message.role === 'assistant' && item.message.suggestions?.length && isLast && !isTyping;
|
|
27367
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(Message, { message: item.message, showTimestamp: showTimestamps,
|
|
27457
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsx(Message, { message: item.message, showTimestamp: showTimestamps, onFeedback: onFeedback, getActionRenderer: getActionRenderer, accentColor: accentColor }), hasFollowUp && onSuggestedQuestionClick && jsxRuntime.jsx(FollowUpSuggestions, { suggestions: item.message.suggestions, onQuestionClick: onSuggestedQuestionClick, onActionClick: onActionClick, accentColor: accentColor })] }, item.message.id));
|
|
27368
27458
|
}), isTyping && showTypingIndicator && !hasActiveAction && messages.length > 0 && jsxRuntime.jsx(TypingIndicator, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }));
|
|
27369
27459
|
};
|
|
27370
27460
|
|
|
@@ -27379,7 +27469,7 @@ const formatFileSize = (bytes) => {
|
|
|
27379
27469
|
return (bytes / 1024).toFixed(1) + ' KB';
|
|
27380
27470
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
27381
27471
|
};
|
|
27382
|
-
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, }) => {
|
|
27383
27473
|
const [value, setValue] = React.useState('');
|
|
27384
27474
|
const [selectedFiles, setSelectedFiles] = React.useState([]);
|
|
27385
27475
|
const textareaRef = React.useRef(null);
|
|
@@ -27414,10 +27504,10 @@ const MessageInput = ({ onSend, placeholder = 'Type your message...', disabled =
|
|
|
27414
27504
|
}
|
|
27415
27505
|
};
|
|
27416
27506
|
const canSend = value.trim() || selectedFiles.length > 0;
|
|
27417
|
-
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" })] }))] }))] }));
|
|
27418
27508
|
};
|
|
27419
27509
|
|
|
27420
|
-
function groupSlotsByDate(slots) {
|
|
27510
|
+
function groupSlotsByDate$1(slots) {
|
|
27421
27511
|
const grouped = new Map();
|
|
27422
27512
|
for (const slot of slots) {
|
|
27423
27513
|
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
@@ -27431,7 +27521,7 @@ function groupSlotsByDate(slots) {
|
|
|
27431
27521
|
}
|
|
27432
27522
|
return grouped;
|
|
27433
27523
|
}
|
|
27434
|
-
function formatDate(dateStr) {
|
|
27524
|
+
function formatDate$1(dateStr) {
|
|
27435
27525
|
try {
|
|
27436
27526
|
const date = new Date(dateStr);
|
|
27437
27527
|
return new Intl.DateTimeFormat("en-US", {
|
|
@@ -27444,16 +27534,16 @@ function formatDate(dateStr) {
|
|
|
27444
27534
|
return dateStr;
|
|
27445
27535
|
}
|
|
27446
27536
|
}
|
|
27447
|
-
function CalendarIcon() {
|
|
27537
|
+
function CalendarIcon$1() {
|
|
27448
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" }) }));
|
|
27449
27539
|
}
|
|
27450
|
-
function CheckIcon() {
|
|
27540
|
+
function CheckIcon$1() {
|
|
27451
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" }) }));
|
|
27452
27542
|
}
|
|
27453
|
-
function ExternalLinkIcon() {
|
|
27543
|
+
function ExternalLinkIcon$2() {
|
|
27454
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" })] }));
|
|
27455
27545
|
}
|
|
27456
|
-
function Skeleton({ width, height, borderRadius = '4px' }) {
|
|
27546
|
+
function Skeleton$1({ width, height, borderRadius = '4px' }) {
|
|
27457
27547
|
return (jsxRuntime.jsx("div", { className: "ai-chat-action-skeleton-item", style: { width, height, borderRadius } }));
|
|
27458
27548
|
}
|
|
27459
27549
|
function GoogleCalendarCard({ action, onComplete, accentColor, className = '' }) {
|
|
@@ -27470,13 +27560,12 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
|
|
|
27470
27560
|
: [];
|
|
27471
27561
|
const allowTopic = state.allowTopic !== false;
|
|
27472
27562
|
const isBooked = state.status === "booked";
|
|
27473
|
-
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
27563
|
+
const slotsByDate = groupSlotsByDate$1(availableSlots);
|
|
27474
27564
|
const dates = Array.from(slotsByDate.keys()).sort();
|
|
27475
27565
|
const [selectedDate, setSelectedDate] = React.useState(dates[0] ?? "");
|
|
27476
27566
|
const [selectedSlot, setSelectedSlot] = React.useState(null);
|
|
27477
27567
|
const [topic, setTopic] = React.useState("");
|
|
27478
27568
|
const [error, setError] = React.useState(null);
|
|
27479
|
-
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
27480
27569
|
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
27481
27570
|
const accentStyle = accentColor ? { '--action-accent': accentColor } : {};
|
|
27482
27571
|
const onConfirm = () => {
|
|
@@ -27489,8 +27578,245 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
|
|
|
27489
27578
|
return;
|
|
27490
27579
|
}
|
|
27491
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);
|
|
27492
27815
|
setIsSubmitting(true);
|
|
27493
|
-
|
|
27816
|
+
console.log('[MicrosoftCalendarCard] Confirming appointment:', {
|
|
27817
|
+
slot: selectedSlot,
|
|
27818
|
+
topic: topic.trim()
|
|
27819
|
+
});
|
|
27494
27820
|
setTimeout(() => {
|
|
27495
27821
|
onComplete?.(action.toolCallId, {
|
|
27496
27822
|
...action.state,
|
|
@@ -27502,22 +27828,566 @@ function GoogleCalendarCard({ action, onComplete, accentColor, className = '' })
|
|
|
27502
27828
|
});
|
|
27503
27829
|
}, 50);
|
|
27504
27830
|
};
|
|
27505
|
-
//
|
|
27506
|
-
|
|
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") {
|
|
27507
27853
|
const bookedSlot = state.selectedSlot;
|
|
27508
27854
|
const bookedTopic = state.topic;
|
|
27509
27855
|
const eventLink = state.bookedEventLink;
|
|
27510
|
-
|
|
27511
|
-
|
|
27512
|
-
|
|
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
|
|
27513
27888
|
if (isSubmitting) {
|
|
27514
|
-
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.
|
|
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;
|
|
27974
|
+
}
|
|
27975
|
+
|
|
27976
|
+
function truncate(text, maxLength) {
|
|
27977
|
+
if (text.length <= maxLength)
|
|
27978
|
+
return text;
|
|
27979
|
+
return text.slice(0, maxLength).trim() + '...';
|
|
27980
|
+
}
|
|
27981
|
+
function ExternalLinkIcon() {
|
|
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" })] }));
|
|
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
|
+
}
|
|
28002
|
+
function LinkPreviewCard({ action, onComplete, accentColor }) {
|
|
28003
|
+
const rawState = action.state;
|
|
28004
|
+
const hasCompletedRef = React.useRef(false);
|
|
28005
|
+
// Provide safe defaults if state is missing
|
|
28006
|
+
const state = {
|
|
28007
|
+
links: rawState?.links || [],
|
|
28008
|
+
context: rawState?.context,
|
|
28009
|
+
status: rawState?.status || 'displaying',
|
|
28010
|
+
error: rawState?.error,
|
|
28011
|
+
};
|
|
28012
|
+
const isError = state.status === 'error';
|
|
28013
|
+
// Auto-complete on mount so AI can continue generating text response
|
|
28014
|
+
React.useEffect(() => {
|
|
28015
|
+
if (!action.done && !hasCompletedRef.current && onComplete && state.links.length > 0) {
|
|
28016
|
+
hasCompletedRef.current = true;
|
|
28017
|
+
// Signal completion immediately - the card is displayed, AI can continue
|
|
28018
|
+
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
28019
|
+
}
|
|
28020
|
+
}, [action.done, action.toolCallId, onComplete, state]);
|
|
28021
|
+
const handleLinkClick = (url) => {
|
|
28022
|
+
if (url) {
|
|
28023
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
28024
|
+
}
|
|
28025
|
+
onComplete?.(action.toolCallId, { ...state, status: 'clicked' });
|
|
28026
|
+
};
|
|
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' }) }) }));
|
|
27515
28029
|
}
|
|
27516
|
-
|
|
27517
|
-
|
|
27518
|
-
|
|
27519
|
-
|
|
27520
|
-
|
|
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))) })] }));
|
|
28038
|
+
}
|
|
28039
|
+
|
|
28040
|
+
function PlayIcon() {
|
|
28041
|
+
return (jsxRuntime.jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "currentColor", stroke: "none", children: jsxRuntime.jsx("path", { d: "M8 5v14l11-7z" }) }));
|
|
28042
|
+
}
|
|
28043
|
+
function getProviderLabel(provider) {
|
|
28044
|
+
switch (provider) {
|
|
28045
|
+
case 'youtube':
|
|
28046
|
+
return 'YouTube';
|
|
28047
|
+
case 'vimeo':
|
|
28048
|
+
return 'Vimeo';
|
|
28049
|
+
case 'loom':
|
|
28050
|
+
return 'Loom';
|
|
28051
|
+
case 'direct':
|
|
28052
|
+
return 'Video';
|
|
28053
|
+
default:
|
|
28054
|
+
return 'Video';
|
|
28055
|
+
}
|
|
28056
|
+
}
|
|
28057
|
+
function VideoPlayerCard({ action, onComplete, accentColor }) {
|
|
28058
|
+
const rawState = action.state;
|
|
28059
|
+
const hasCompletedRef = React.useRef(false);
|
|
28060
|
+
const [isPlaying, setIsPlaying] = React.useState(false);
|
|
28061
|
+
// Provide safe defaults if state is missing
|
|
28062
|
+
const state = {
|
|
28063
|
+
url: rawState?.url || '',
|
|
28064
|
+
title: rawState?.title,
|
|
28065
|
+
context: rawState?.context,
|
|
28066
|
+
provider: rawState?.provider || 'direct',
|
|
28067
|
+
embedUrl: rawState?.embedUrl || '',
|
|
28068
|
+
thumbnailUrl: rawState?.thumbnailUrl,
|
|
28069
|
+
videoId: rawState?.videoId,
|
|
28070
|
+
status: rawState?.status || 'displaying',
|
|
28071
|
+
error: rawState?.error,
|
|
28072
|
+
};
|
|
28073
|
+
const isError = state.status === 'error';
|
|
28074
|
+
// Auto-complete on mount so AI can continue generating text response
|
|
28075
|
+
React.useEffect(() => {
|
|
28076
|
+
if (!action.done && !hasCompletedRef.current && onComplete && state.embedUrl) {
|
|
28077
|
+
hasCompletedRef.current = true;
|
|
28078
|
+
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
28079
|
+
}
|
|
28080
|
+
}, [action.done, action.toolCallId, onComplete, state]);
|
|
28081
|
+
const handlePlay = () => {
|
|
28082
|
+
setIsPlaying(true);
|
|
28083
|
+
onComplete?.(action.toolCallId, { ...state, status: 'played' });
|
|
28084
|
+
};
|
|
28085
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
28086
|
+
// Build embed URL with autoplay when playing
|
|
28087
|
+
const getEmbedSrc = () => {
|
|
28088
|
+
if (!isPlaying)
|
|
28089
|
+
return '';
|
|
28090
|
+
let src = state.embedUrl;
|
|
28091
|
+
const separator = src.includes('?') ? '&' : '?';
|
|
28092
|
+
switch (state.provider) {
|
|
28093
|
+
case 'youtube':
|
|
28094
|
+
return `${src}${separator}autoplay=1&rel=0`;
|
|
28095
|
+
case 'vimeo':
|
|
28096
|
+
return `${src}${separator}autoplay=1`;
|
|
28097
|
+
case 'loom':
|
|
28098
|
+
return `${src}${separator}autoplay=1`;
|
|
28099
|
+
default:
|
|
28100
|
+
return src;
|
|
28101
|
+
}
|
|
28102
|
+
};
|
|
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 }))] }));
|
|
28104
|
+
}
|
|
28105
|
+
|
|
28106
|
+
function MapPinIcon() {
|
|
28107
|
+
return (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" }), jsxRuntime.jsx("circle", { cx: "12", cy: "10", r: "3" })] }));
|
|
28108
|
+
}
|
|
28109
|
+
function PhoneIcon() {
|
|
28110
|
+
return (jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("path", { d: "M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" }) }));
|
|
28111
|
+
}
|
|
28112
|
+
function ClockIcon() {
|
|
28113
|
+
return (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }), jsxRuntime.jsx("polyline", { points: "12 6 12 12 16 14" })] }));
|
|
28114
|
+
}
|
|
28115
|
+
function NavigationIcon() {
|
|
28116
|
+
return (jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polygon", { points: "3 11 22 2 13 21 11 13 3 11" }) }));
|
|
28117
|
+
}
|
|
28118
|
+
function GlobeIcon() {
|
|
28119
|
+
return (jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }), jsxRuntime.jsx("line", { x1: "2", y1: "12", x2: "22", y2: "12" }), jsxRuntime.jsx("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" })] }));
|
|
28120
|
+
}
|
|
28121
|
+
function ChevronIcon({ direction }) {
|
|
28122
|
+
return (jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: { transform: direction === 'up' ? 'rotate(180deg)' : 'none' }, children: jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) }));
|
|
28123
|
+
}
|
|
28124
|
+
function getOpenStatus(hours) {
|
|
28125
|
+
if (!hours || hours.length === 0)
|
|
28126
|
+
return null;
|
|
28127
|
+
const now = new Date();
|
|
28128
|
+
const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
28129
|
+
const today = dayNames[now.getDay()];
|
|
28130
|
+
const todayHours = hours.find(h => h.day === today);
|
|
28131
|
+
if (!todayHours || todayHours.closed)
|
|
28132
|
+
return false;
|
|
28133
|
+
const currentTime = now.getHours() * 100 + now.getMinutes();
|
|
28134
|
+
const openTime = parseInt(todayHours.open.replace(':', ''));
|
|
28135
|
+
const closeTime = parseInt(todayHours.close.replace(':', ''));
|
|
28136
|
+
return currentTime >= openTime && currentTime < closeTime;
|
|
28137
|
+
}
|
|
28138
|
+
function HoursDisplay({ hours, compact = false }) {
|
|
28139
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
28140
|
+
const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
28141
|
+
const today = dayNames[new Date().getDay()];
|
|
28142
|
+
const todayHours = hours.find(h => h.day === today);
|
|
28143
|
+
if (compact && !expanded) {
|
|
28144
|
+
return (jsxRuntime.jsxs("div", { className: "ai-chat-location-card__hours", children: [jsxRuntime.jsx(ClockIcon, {}), jsxRuntime.jsx("span", { children: todayHours?.closed ? 'Closed today' : `${todayHours?.open} - ${todayHours?.close}` })] }));
|
|
28145
|
+
}
|
|
28146
|
+
return (jsxRuntime.jsxs("div", { className: "ai-chat-location-card__hours", children: [jsxRuntime.jsx(ClockIcon, {}), jsxRuntime.jsxs("div", { className: "ai-chat-location-card__hours-list", children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => setExpanded(!expanded), className: "ai-chat-location-card__hours-toggle", children: ["Today: ", todayHours?.closed ? 'Closed' : `${todayHours?.open} - ${todayHours?.close}`, jsxRuntime.jsx(ChevronIcon, { direction: expanded ? 'up' : 'down' })] }), expanded && (jsxRuntime.jsx("ul", { className: "ai-chat-location-card__hours-full", children: hours.map(h => (jsxRuntime.jsxs("li", { className: h.day === today ? 'ai-chat-location-card__hours-today' : '', children: [jsxRuntime.jsx("span", { children: h.day }), jsxRuntime.jsx("span", { children: h.closed ? 'Closed' : `${h.open} - ${h.close}` })] }, h.day))) }))] })] }));
|
|
28147
|
+
}
|
|
28148
|
+
function LocationItem({ location, settings, accentColor, onDirections, showMap = true, compact = false, }) {
|
|
28149
|
+
const openStatus = getOpenStatus(location.hours);
|
|
28150
|
+
const mapHeight = settings.mapHeight || 180;
|
|
28151
|
+
const mapZoom = settings.mapZoom || 15;
|
|
28152
|
+
const getMapEmbedUrl = () => {
|
|
28153
|
+
const query = location.lat && location.lng
|
|
28154
|
+
? `${location.lat},${location.lng}`
|
|
28155
|
+
: encodeURIComponent(location.address);
|
|
28156
|
+
return `https://www.google.com/maps/embed/v1/place?key=AIzaSyBFw0Qbyq9zTFTd-tUY6dZWTgaQzuU17R8&q=${query}&zoom=${mapZoom}`;
|
|
28157
|
+
};
|
|
28158
|
+
const handleCall = () => {
|
|
28159
|
+
if (location.phone) {
|
|
28160
|
+
window.location.href = `tel:${location.phone}`;
|
|
28161
|
+
}
|
|
28162
|
+
};
|
|
28163
|
+
const style = accentColor ? { '--action-accent': accentColor } : undefined;
|
|
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"] }))] })] })] }));
|
|
28167
|
+
}
|
|
28168
|
+
function LocationCard({ action, onComplete, accentColor, maxColumns = 3 }) {
|
|
28169
|
+
const rawState = action.state;
|
|
28170
|
+
const hasCompletedRef = React.useRef(false);
|
|
28171
|
+
const state = {
|
|
28172
|
+
locations: rawState?.locations || [],
|
|
28173
|
+
settings: rawState?.settings || {},
|
|
28174
|
+
matchInfo: rawState?.matchInfo,
|
|
28175
|
+
status: rawState?.status || 'displaying',
|
|
28176
|
+
};
|
|
28177
|
+
const { locations, settings } = state;
|
|
28178
|
+
const layout = settings.multiLocationLayout || 'stack';
|
|
28179
|
+
const isSingleLocation = locations.length === 1;
|
|
28180
|
+
const stackColumns = Math.min(Math.max(locations.length, 1), maxColumns);
|
|
28181
|
+
React.useEffect(() => {
|
|
28182
|
+
if (!action.done && !hasCompletedRef.current && onComplete && locations.length > 0) {
|
|
28183
|
+
hasCompletedRef.current = true;
|
|
28184
|
+
onComplete(action.toolCallId, { ...state, status: 'displaying' });
|
|
28185
|
+
}
|
|
28186
|
+
}, [action.done, action.toolCallId, onComplete, state, locations.length]);
|
|
28187
|
+
const handleDirections = (location) => {
|
|
28188
|
+
const url = location.lat && location.lng
|
|
28189
|
+
? `https://www.google.com/maps/dir/?api=1&destination=${location.lat},${location.lng}`
|
|
28190
|
+
: `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(location.address)}`;
|
|
28191
|
+
window.open(url, '_blank', 'noopener,noreferrer');
|
|
28192
|
+
onComplete?.(action.toolCallId, { ...state, status: 'directions_opened' });
|
|
28193
|
+
};
|
|
28194
|
+
if (locations.length === 0) {
|
|
28195
|
+
return (jsxRuntime.jsx("div", { className: "ai-chat-location-card ai-chat-location-card--error", children: jsxRuntime.jsx("p", { children: "No locations to display" }) }));
|
|
28196
|
+
}
|
|
28197
|
+
if (isSingleLocation) {
|
|
28198
|
+
return (jsxRuntime.jsx(LocationItem, { location: locations[0], settings: settings, accentColor: accentColor, onDirections: () => handleDirections(locations[0]), showMap: true }));
|
|
28199
|
+
}
|
|
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 : {
|
|
28282
|
+
gridTemplateColumns: `repeat(${stackColumns}, minmax(0, 1fr))`,
|
|
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') }))] })] }));
|
|
27521
28391
|
}
|
|
27522
28392
|
|
|
27523
28393
|
const pendingResolvers = new Map();
|
|
@@ -27530,12 +28400,6 @@ function getFrontendActionHandler(implementation) {
|
|
|
27530
28400
|
function getActionRenderer(implementation) {
|
|
27531
28401
|
return actionRenderers[implementation];
|
|
27532
28402
|
}
|
|
27533
|
-
function getActionPrompt(implementation) {
|
|
27534
|
-
if (implementation === "google-calendar-appointment") {
|
|
27535
|
-
return "Select a date to continue.";
|
|
27536
|
-
}
|
|
27537
|
-
return "Action input required.";
|
|
27538
|
-
}
|
|
27539
28403
|
function waitForActionState(toolCallId) {
|
|
27540
28404
|
return new Promise((resolve) => {
|
|
27541
28405
|
pendingResolvers.set(toolCallId, resolve);
|
|
@@ -27562,26 +28426,272 @@ function unregisterActionResumeCallback(toolCallId) {
|
|
|
27562
28426
|
resumeCallbacks.delete(toolCallId);
|
|
27563
28427
|
}
|
|
27564
28428
|
|
|
27565
|
-
|
|
27566
|
-
|
|
27567
|
-
|
|
28429
|
+
function registerGoogleCalendarHandler() {
|
|
28430
|
+
frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
|
|
28431
|
+
return waitForActionState(context.toolCallId);
|
|
28432
|
+
};
|
|
28433
|
+
}
|
|
27568
28434
|
|
|
27569
|
-
|
|
27570
|
-
|
|
27571
|
-
|
|
27572
|
-
|
|
27573
|
-
|
|
27574
|
-
|
|
28435
|
+
/**
|
|
28436
|
+
* Register google-calendar-appointment action handler and renderer.
|
|
28437
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
28438
|
+
*/
|
|
28439
|
+
function registerGoogleCalendarAction() {
|
|
28440
|
+
// Register the handler
|
|
28441
|
+
registerGoogleCalendarHandler();
|
|
28442
|
+
// Register the renderer
|
|
28443
|
+
actionRenderers["google-calendar-appointment"] = (message, accentColor) => {
|
|
28444
|
+
const action = message.action;
|
|
28445
|
+
if (!action)
|
|
28446
|
+
return null;
|
|
28447
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28448
|
+
resolveActionState(toolCallId, newState);
|
|
28449
|
+
};
|
|
28450
|
+
return (jsxRuntime.jsx(GoogleCalendarCard, { action: {
|
|
28451
|
+
implementation: action.implementation,
|
|
28452
|
+
toolCallId: action.toolCallId,
|
|
28453
|
+
actionId: action.actionId,
|
|
28454
|
+
input: action.input,
|
|
28455
|
+
state: action.state,
|
|
28456
|
+
done: action.done ?? false,
|
|
28457
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
27575
28458
|
};
|
|
27576
|
-
|
|
27577
|
-
|
|
27578
|
-
|
|
27579
|
-
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27584
|
-
|
|
28459
|
+
}
|
|
28460
|
+
|
|
28461
|
+
function registerMicrosoftCalendarHandler() {
|
|
28462
|
+
frontendActionHandlers["microsoft-calendar-appointment"] = async (_input, _state, context) => {
|
|
28463
|
+
return waitForActionState(context.toolCallId);
|
|
28464
|
+
};
|
|
28465
|
+
}
|
|
28466
|
+
|
|
28467
|
+
/**
|
|
28468
|
+
* Register microsoft-calendar-appointment action handler and renderer.
|
|
28469
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
28470
|
+
*/
|
|
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;
|
|
28505
|
+
if (!action)
|
|
28506
|
+
return null;
|
|
28507
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28508
|
+
resolveActionState(toolCallId, newState);
|
|
28509
|
+
};
|
|
28510
|
+
// Check if action state indicates it's already complete (displaying or clicked)
|
|
28511
|
+
const state = action.state;
|
|
28512
|
+
const status = state?.status;
|
|
28513
|
+
const isDone = action.done || status === "displaying" || status === "clicked";
|
|
28514
|
+
return (jsxRuntime.jsx(LinkPreviewCard, { action: {
|
|
28515
|
+
implementation: action.implementation,
|
|
28516
|
+
toolCallId: action.toolCallId,
|
|
28517
|
+
actionId: action.actionId,
|
|
28518
|
+
input: action.input,
|
|
28519
|
+
state: action.state,
|
|
28520
|
+
done: isDone,
|
|
28521
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
28522
|
+
};
|
|
28523
|
+
}
|
|
28524
|
+
|
|
28525
|
+
/**
|
|
28526
|
+
* Register video-player action handler and renderer.
|
|
28527
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
28528
|
+
*/
|
|
28529
|
+
function registerVideoPlayerAction() {
|
|
28530
|
+
// Handler - auto-completes immediately since no user input is needed
|
|
28531
|
+
frontendActionHandlers["video-player"] = async (_input, state, _context) => {
|
|
28532
|
+
return { ...state, status: "displaying" };
|
|
28533
|
+
};
|
|
28534
|
+
// Renderer - displays the embedded video player card
|
|
28535
|
+
actionRenderers["video-player"] = (message, accentColor) => {
|
|
28536
|
+
const action = message.action;
|
|
28537
|
+
if (!action)
|
|
28538
|
+
return null;
|
|
28539
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28540
|
+
resolveActionState(toolCallId, newState);
|
|
28541
|
+
};
|
|
28542
|
+
// Check if action state indicates it's already complete (displaying or played)
|
|
28543
|
+
const state = action.state;
|
|
28544
|
+
const status = state?.status;
|
|
28545
|
+
const isDone = action.done || status === "displaying" || status === "played";
|
|
28546
|
+
return (jsxRuntime.jsx(VideoPlayerCard, { action: {
|
|
28547
|
+
implementation: action.implementation,
|
|
28548
|
+
toolCallId: action.toolCallId,
|
|
28549
|
+
actionId: action.actionId,
|
|
28550
|
+
input: action.input,
|
|
28551
|
+
state: action.state,
|
|
28552
|
+
done: isDone,
|
|
28553
|
+
}, onComplete: handleComplete, accentColor: accentColor }));
|
|
28554
|
+
};
|
|
28555
|
+
}
|
|
28556
|
+
|
|
28557
|
+
/**
|
|
28558
|
+
* Register location-card action handler and renderer.
|
|
28559
|
+
* Called by initializeActionHandlers to prevent tree-shaking.
|
|
28560
|
+
*/
|
|
28561
|
+
function registerLocationCardAction() {
|
|
28562
|
+
// Handler - auto-completes immediately since no user input is needed
|
|
28563
|
+
frontendActionHandlers["location-card"] = async (_input, state, _context) => {
|
|
28564
|
+
return { ...state, status: "displaying" };
|
|
28565
|
+
};
|
|
28566
|
+
// Renderer - displays the location card
|
|
28567
|
+
actionRenderers["location-card"] = (message, accentColor, variant) => {
|
|
28568
|
+
const action = message.action;
|
|
28569
|
+
if (!action)
|
|
28570
|
+
return null;
|
|
28571
|
+
const handleComplete = (toolCallId, newState) => {
|
|
28572
|
+
resolveActionState(toolCallId, newState);
|
|
28573
|
+
};
|
|
28574
|
+
// Check if action state indicates it's already complete
|
|
28575
|
+
const state = action.state;
|
|
28576
|
+
const status = state?.status;
|
|
28577
|
+
const isDone = action.done || status === "displaying" || status === "directions_opened";
|
|
28578
|
+
return (jsxRuntime.jsx(LocationCard, { action: {
|
|
28579
|
+
implementation: action.implementation,
|
|
28580
|
+
toolCallId: action.toolCallId,
|
|
28581
|
+
actionId: action.actionId,
|
|
28582
|
+
input: action.input,
|
|
28583
|
+
state: action.state,
|
|
28584
|
+
done: isDone,
|
|
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 }));
|
|
28671
|
+
};
|
|
28672
|
+
}
|
|
28673
|
+
|
|
28674
|
+
// Track if handlers have been initialized
|
|
28675
|
+
let initialized = false;
|
|
28676
|
+
/**
|
|
28677
|
+
* Initialize all action handlers.
|
|
28678
|
+
* Call this to ensure handlers are registered (prevents tree-shaking in production builds).
|
|
28679
|
+
* Safe to call multiple times - will only register once.
|
|
28680
|
+
*/
|
|
28681
|
+
function initializeActionHandlers() {
|
|
28682
|
+
if (initialized)
|
|
28683
|
+
return;
|
|
28684
|
+
initialized = true;
|
|
28685
|
+
// Explicitly call each registration function to prevent tree-shaking
|
|
28686
|
+
registerGoogleCalendarAction();
|
|
28687
|
+
registerMicrosoftCalendarAction();
|
|
28688
|
+
registerLinkPreviewAction();
|
|
28689
|
+
registerVideoPlayerAction();
|
|
28690
|
+
registerLocationCardAction();
|
|
28691
|
+
registerQueryContactDirectoryAction();
|
|
28692
|
+
registerContactCardAction();
|
|
28693
|
+
registerDisplayFormAction();
|
|
28694
|
+
}
|
|
27585
28695
|
|
|
27586
28696
|
/**
|
|
27587
28697
|
* Local Storage Utilities
|
|
@@ -27800,10 +28910,6 @@ function isStorageAvailable() {
|
|
|
27800
28910
|
}
|
|
27801
28911
|
}
|
|
27802
28912
|
|
|
27803
|
-
/**
|
|
27804
|
-
* useChat Hook
|
|
27805
|
-
* Main state management for chat functionality
|
|
27806
|
-
*/
|
|
27807
28913
|
function hydrateToolNames(messages) {
|
|
27808
28914
|
const toolCallNameById = new Map();
|
|
27809
28915
|
for (const entry of messages) {
|
|
@@ -27847,81 +28953,77 @@ function hydrateToolNames(messages) {
|
|
|
27847
28953
|
};
|
|
27848
28954
|
});
|
|
27849
28955
|
}
|
|
27850
|
-
function hydrateActionContent(messages) {
|
|
27851
|
-
return messages.map((entry) => {
|
|
27852
|
-
if (entry.message.role !== "assistant" || !entry.action) {
|
|
27853
|
-
return entry;
|
|
27854
|
-
}
|
|
27855
|
-
const content = typeof entry.message.content === "string" ? entry.message.content : "";
|
|
27856
|
-
if (content.trim().length > 0) {
|
|
27857
|
-
return entry;
|
|
27858
|
-
}
|
|
27859
|
-
return {
|
|
27860
|
-
...entry,
|
|
27861
|
-
message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
|
|
27862
|
-
};
|
|
27863
|
-
});
|
|
27864
|
-
}
|
|
27865
28956
|
function hydrateMessages(messages) {
|
|
27866
|
-
return
|
|
28957
|
+
return hydrateToolNames(messages);
|
|
27867
28958
|
}
|
|
27868
|
-
|
|
27869
|
-
|
|
27870
|
-
|
|
27871
|
-
|
|
27872
|
-
|
|
27873
|
-
|
|
27874
|
-
|
|
27875
|
-
|
|
27876
|
-
|
|
27877
|
-
|
|
27878
|
-
|
|
27879
|
-
|
|
27880
|
-
|
|
27881
|
-
|
|
27882
|
-
|
|
27883
|
-
|
|
27884
|
-
}
|
|
27885
|
-
: m),
|
|
27886
|
-
isTyping: true,
|
|
27887
|
-
}));
|
|
27888
|
-
const streamState = createStreamState();
|
|
27889
|
-
// Continue the agent stream with the new state
|
|
27890
|
-
for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
|
|
27891
|
-
if (event.type === "done") {
|
|
27892
|
-
finalizeToolMessage(streamState, setState, toolCallId, toolName);
|
|
27893
|
-
streamState.sources = event.sources;
|
|
27894
|
-
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
27895
|
-
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
27896
|
-
continue;
|
|
27897
|
-
}
|
|
27898
|
-
if (event.type === "error") {
|
|
27899
|
-
const errorMessage = {
|
|
27900
|
-
id: generateMessageId(),
|
|
27901
|
-
message: {
|
|
27902
|
-
role: "assistant",
|
|
27903
|
-
content: "Sorry, an error occurred. Please try again later.",
|
|
27904
|
-
},
|
|
27905
|
-
timestamp: new Date().toISOString(),
|
|
27906
|
-
sources: [],
|
|
27907
|
-
isError: true,
|
|
27908
|
-
};
|
|
27909
|
-
upsertMessage(setState, errorMessage, false);
|
|
27910
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
27911
|
-
return;
|
|
27912
|
-
}
|
|
27913
|
-
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
27914
|
-
}
|
|
27915
|
-
setState(prev => ({ ...prev, isTyping: false }));
|
|
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.`;
|
|
27916
28975
|
}
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
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.';
|
|
27920
29004
|
}
|
|
27921
|
-
});
|
|
27922
29005
|
}
|
|
29006
|
+
return { message, retryAfterSeconds, status: error.status };
|
|
27923
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.' };
|
|
29012
|
+
}
|
|
29013
|
+
if (lower.includes('timeout')) {
|
|
29014
|
+
return { message: 'The request timed out. Please try again.' };
|
|
29015
|
+
}
|
|
29016
|
+
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
29017
|
+
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
29018
|
+
}
|
|
29019
|
+
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
29020
|
+
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
29021
|
+
}
|
|
29022
|
+
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
29023
|
+
}
|
|
29024
|
+
return { message: 'Something went wrong. Please try again.' };
|
|
27924
29025
|
}
|
|
29026
|
+
|
|
27925
29027
|
function createStreamState() {
|
|
27926
29028
|
return {
|
|
27927
29029
|
currentContent: "",
|
|
@@ -27930,6 +29032,7 @@ function createStreamState() {
|
|
|
27930
29032
|
newMessageIds: new Set(),
|
|
27931
29033
|
sources: [],
|
|
27932
29034
|
toolCallToActionId: {},
|
|
29035
|
+
requestId: generateMessageId(),
|
|
27933
29036
|
};
|
|
27934
29037
|
}
|
|
27935
29038
|
function upsertMessage(setState, message, isTyping) {
|
|
@@ -27965,15 +29068,40 @@ function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionI
|
|
|
27965
29068
|
return msg;
|
|
27966
29069
|
}
|
|
27967
29070
|
// Attach suggestions only to the last assistant message
|
|
27968
|
-
|
|
27969
|
-
|
|
27970
|
-
|
|
27971
|
-
return { ...msg, sources, toolCallToActionId };
|
|
29071
|
+
const withSuggestions = index === lastAssistantIndex && suggestions && suggestions.length > 0
|
|
29072
|
+
? { suggestions }
|
|
29073
|
+
: {};
|
|
29074
|
+
return { ...msg, sources, toolCallToActionId, ...withSuggestions };
|
|
27972
29075
|
}),
|
|
27973
29076
|
isTyping: false,
|
|
27974
29077
|
};
|
|
27975
29078
|
});
|
|
27976
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
|
+
|
|
27977
29105
|
function handleContentEvent(event, streamState, onMessageUpdate, setState) {
|
|
27978
29106
|
streamState.currentContent += event.content;
|
|
27979
29107
|
const assistantMessage = {
|
|
@@ -28020,8 +29148,6 @@ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
|
|
|
28020
29148
|
}
|
|
28021
29149
|
function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
28022
29150
|
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
28023
|
-
// Update state and mark action as done in a single setState call
|
|
28024
|
-
// Keep isTyping: true because the agent may continue generating content after tool completion
|
|
28025
29151
|
setState(prev => {
|
|
28026
29152
|
const messages = prev.messages.map((msg) => {
|
|
28027
29153
|
const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
|
|
@@ -28029,7 +29155,26 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
|
28029
29155
|
return msg;
|
|
28030
29156
|
}
|
|
28031
29157
|
const existingName = msg.message.name || event.tool_name;
|
|
28032
|
-
|
|
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 = {
|
|
28033
29178
|
...msg,
|
|
28034
29179
|
message: {
|
|
28035
29180
|
role: "tool",
|
|
@@ -28039,14 +29184,10 @@ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
|
28039
29184
|
},
|
|
28040
29185
|
isStreaming: false,
|
|
28041
29186
|
toolExecuting: existingName,
|
|
28042
|
-
action
|
|
28043
|
-
...msg.action,
|
|
28044
|
-
state: event.state || msg.action.state,
|
|
28045
|
-
done: true, // Mark action as completed
|
|
28046
|
-
} : undefined,
|
|
29187
|
+
action,
|
|
28047
29188
|
};
|
|
29189
|
+
return updatedMsg;
|
|
28048
29190
|
});
|
|
28049
|
-
// Keep typing indicator visible - it will be hidden by done/finalizeStreamMessages
|
|
28050
29191
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
28051
29192
|
});
|
|
28052
29193
|
}
|
|
@@ -28078,34 +29219,6 @@ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
|
|
|
28078
29219
|
return { ...prev, messages, isTyping: true, isLoading: false };
|
|
28079
29220
|
});
|
|
28080
29221
|
}
|
|
28081
|
-
function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
|
|
28082
|
-
setState(prev => {
|
|
28083
|
-
const messages = prev.messages.map((entry) => {
|
|
28084
|
-
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
|
|
28085
|
-
if (!matchesToolCall) {
|
|
28086
|
-
return entry;
|
|
28087
|
-
}
|
|
28088
|
-
const existingName = entry.message.name || toolName;
|
|
28089
|
-
return {
|
|
28090
|
-
...entry,
|
|
28091
|
-
message: {
|
|
28092
|
-
role: "tool",
|
|
28093
|
-
content: typeof entry.message.content === "string" ? entry.message.content : "",
|
|
28094
|
-
tool_call_id: toolCallId,
|
|
28095
|
-
name: existingName,
|
|
28096
|
-
},
|
|
28097
|
-
isStreaming: false,
|
|
28098
|
-
toolExecuting: existingName,
|
|
28099
|
-
action: entry.action ? {
|
|
28100
|
-
...entry.action,
|
|
28101
|
-
done: true, // Mark action as completed
|
|
28102
|
-
} : undefined,
|
|
28103
|
-
};
|
|
28104
|
-
});
|
|
28105
|
-
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
28106
|
-
});
|
|
28107
|
-
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
28108
|
-
}
|
|
28109
29222
|
function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
|
|
28110
29223
|
streamState.sources = event.sources;
|
|
28111
29224
|
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
@@ -28164,6 +29277,7 @@ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
|
|
|
28164
29277
|
console.warn('[Chat] Unknown event type:', event.type);
|
|
28165
29278
|
}
|
|
28166
29279
|
}
|
|
29280
|
+
|
|
28167
29281
|
async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
|
|
28168
29282
|
let pendingEvent = initialEvent;
|
|
28169
29283
|
while (pendingEvent) {
|
|
@@ -28190,7 +29304,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28190
29304
|
actionId: pendingEvent.action_id,
|
|
28191
29305
|
input: pendingEvent.input,
|
|
28192
29306
|
state: pendingEvent.state,
|
|
28193
|
-
done: false,
|
|
29307
|
+
done: pendingEvent.done ?? false,
|
|
28194
29308
|
},
|
|
28195
29309
|
};
|
|
28196
29310
|
if (streamState.activeToolCallCount === 0) {
|
|
@@ -28204,7 +29318,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28204
29318
|
id: generateMessageId(),
|
|
28205
29319
|
message: {
|
|
28206
29320
|
role: "assistant",
|
|
28207
|
-
content: "Sorry, an error occurred.
|
|
29321
|
+
content: "Sorry, an error occurred.",
|
|
28208
29322
|
},
|
|
28209
29323
|
timestamp: new Date().toISOString(),
|
|
28210
29324
|
sources: [],
|
|
@@ -28228,7 +29342,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28228
29342
|
console.error("[Widget] Frontend action failed:", error);
|
|
28229
29343
|
const errorMessageEntry = {
|
|
28230
29344
|
id: generateMessageId(),
|
|
28231
|
-
message: { role: "assistant", content: "Sorry, an error occurred.
|
|
29345
|
+
message: { role: "assistant", content: "Sorry, an error occurred." },
|
|
28232
29346
|
timestamp: new Date().toISOString(),
|
|
28233
29347
|
sources: [],
|
|
28234
29348
|
isError: true,
|
|
@@ -28240,12 +29354,7 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28240
29354
|
pendingEvent = null;
|
|
28241
29355
|
const updatedToolMessage = {
|
|
28242
29356
|
...toolMessage,
|
|
28243
|
-
action: toolMessage.action
|
|
28244
|
-
? {
|
|
28245
|
-
...toolMessage.action,
|
|
28246
|
-
state: nextState,
|
|
28247
|
-
}
|
|
28248
|
-
: undefined,
|
|
29357
|
+
action: toolMessage.action ? { ...toolMessage.action, state: nextState } : toolMessage.action,
|
|
28249
29358
|
};
|
|
28250
29359
|
upsertMessage(setState, updatedToolMessage, true);
|
|
28251
29360
|
let streamEnded = false;
|
|
@@ -28255,22 +29364,20 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28255
29364
|
break;
|
|
28256
29365
|
}
|
|
28257
29366
|
if (event.type === "done") {
|
|
28258
|
-
//
|
|
28259
|
-
// updated by tool_end event or by the user's frontend action.
|
|
29367
|
+
// Finalize tool message and stream messages
|
|
28260
29368
|
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
28261
|
-
// Handle the done event but skip the tool finalization part since we already did it
|
|
28262
29369
|
streamState.sources = event.sources;
|
|
28263
29370
|
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
28264
29371
|
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id, event.suggestions);
|
|
28265
29372
|
streamEnded = true;
|
|
28266
|
-
continue;
|
|
29373
|
+
continue;
|
|
28267
29374
|
}
|
|
28268
29375
|
if (event.type === "error") {
|
|
28269
29376
|
const errorMessage = {
|
|
28270
29377
|
id: generateMessageId(),
|
|
28271
29378
|
message: {
|
|
28272
29379
|
role: "assistant",
|
|
28273
|
-
content: "Sorry, an error occurred.
|
|
29380
|
+
content: "Sorry, an error occurred.",
|
|
28274
29381
|
},
|
|
28275
29382
|
timestamp: new Date().toISOString(),
|
|
28276
29383
|
sources: [],
|
|
@@ -28281,73 +29388,79 @@ async function handleActionLoop(client, initialEvent, streamState, onMessageUpda
|
|
|
28281
29388
|
}
|
|
28282
29389
|
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
28283
29390
|
}
|
|
28284
|
-
// If stream ended without a done event
|
|
29391
|
+
// If stream ended without a done event, finalize the tool message
|
|
28285
29392
|
if (!streamEnded && !pendingEvent) {
|
|
28286
29393
|
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
28287
29394
|
}
|
|
28288
29395
|
}
|
|
28289
29396
|
}
|
|
28290
|
-
function
|
|
28291
|
-
|
|
28292
|
-
|
|
28293
|
-
|
|
28294
|
-
|
|
28295
|
-
|
|
28296
|
-
|
|
28297
|
-
|
|
28298
|
-
|
|
28299
|
-
|
|
28300
|
-
|
|
28301
|
-
|
|
28302
|
-
|
|
28303
|
-
|
|
28304
|
-
|
|
28305
|
-
|
|
28306
|
-
|
|
28307
|
-
|
|
28308
|
-
|
|
28309
|
-
|
|
28310
|
-
|
|
28311
|
-
|
|
28312
|
-
|
|
28313
|
-
|
|
28314
|
-
|
|
28315
|
-
|
|
28316
|
-
|
|
28317
|
-
|
|
28318
|
-
|
|
28319
|
-
|
|
28320
|
-
|
|
28321
|
-
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
|
|
28325
|
-
|
|
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 }));
|
|
28326
29448
|
}
|
|
28327
|
-
|
|
28328
|
-
|
|
29449
|
+
catch (error) {
|
|
29450
|
+
console.error("[Action Resume] Failed to continue stream:", error);
|
|
29451
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
28329
29452
|
}
|
|
29453
|
+
});
|
|
28330
29454
|
}
|
|
28331
|
-
return { message, retryAfterSeconds, status: error.status };
|
|
28332
|
-
}
|
|
28333
|
-
if (error instanceof Error) {
|
|
28334
|
-
const lower = error.message.toLowerCase();
|
|
28335
|
-
if (lower.includes('network')) {
|
|
28336
|
-
return { message: 'Unable to connect to the server. Please check your internet connection.' };
|
|
28337
|
-
}
|
|
28338
|
-
if (lower.includes('timeout')) {
|
|
28339
|
-
return { message: 'The request timed out. Please try again.' };
|
|
28340
|
-
}
|
|
28341
|
-
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
28342
|
-
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
28343
|
-
}
|
|
28344
|
-
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
28345
|
-
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
28346
|
-
}
|
|
28347
|
-
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
28348
29455
|
}
|
|
28349
|
-
return { message: 'Something went wrong. Please try again.' };
|
|
28350
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();
|
|
28351
29464
|
function useChat(options) {
|
|
28352
29465
|
const { widgetId, apiUrl, currentRoute, onMessage, onError, skipInitialization = false, } = options;
|
|
28353
29466
|
const [state, setState] = React.useState({
|
|
@@ -28356,23 +29469,24 @@ function useChat(options) {
|
|
|
28356
29469
|
isLoading: false,
|
|
28357
29470
|
isTyping: false,
|
|
28358
29471
|
error: null,
|
|
28359
|
-
conversationId: '',
|
|
29472
|
+
conversationId: '',
|
|
28360
29473
|
config: null,
|
|
28361
29474
|
});
|
|
28362
29475
|
const stateRef = React.useRef(state);
|
|
28363
29476
|
React.useEffect(() => {
|
|
28364
29477
|
stateRef.current = state;
|
|
28365
29478
|
}, [state]);
|
|
28366
|
-
// Chat history state
|
|
28367
29479
|
const [conversations, setConversations] = React.useState([]);
|
|
29480
|
+
const abortControllerRef = React.useRef(null);
|
|
29481
|
+
const currentRequestIdRef = React.useRef(null);
|
|
29482
|
+
const lastNewChatTimeRef = React.useRef(0);
|
|
29483
|
+
const NEW_CHAT_COOLDOWN_MS = 5000;
|
|
28368
29484
|
const apiClient = React.useRef(new WidgetApiClient({ widgetId, apiUrl, currentRoute }));
|
|
28369
|
-
// Update API client when currentRoute changes
|
|
28370
29485
|
React.useEffect(() => {
|
|
28371
29486
|
apiClient.current = new WidgetApiClient({ widgetId, apiUrl, currentRoute });
|
|
28372
29487
|
}, [widgetId, apiUrl, currentRoute]);
|
|
28373
29488
|
// Load configuration on mount and hydrate with existing conversation if available
|
|
28374
29489
|
React.useEffect(() => {
|
|
28375
|
-
// Skip initialization in preview mode
|
|
28376
29490
|
if (skipInitialization) {
|
|
28377
29491
|
return;
|
|
28378
29492
|
}
|
|
@@ -28409,7 +29523,7 @@ function useChat(options) {
|
|
|
28409
29523
|
}));
|
|
28410
29524
|
// Setup resume callbacks for incomplete actions
|
|
28411
29525
|
if (conversationId) {
|
|
28412
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
|
|
29526
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
28413
29527
|
}
|
|
28414
29528
|
}
|
|
28415
29529
|
catch (error) {
|
|
@@ -28426,7 +29540,6 @@ function useChat(options) {
|
|
|
28426
29540
|
initialize();
|
|
28427
29541
|
return () => {
|
|
28428
29542
|
isMounted = false;
|
|
28429
|
-
// Cleanup resume callbacks
|
|
28430
29543
|
state.messages.forEach(message => {
|
|
28431
29544
|
if (message.action?.toolCallId) {
|
|
28432
29545
|
unregisterActionResumeCallback(message.action.toolCallId);
|
|
@@ -28449,7 +29562,15 @@ function useChat(options) {
|
|
|
28449
29562
|
const hasFiles = !!files && files.length > 0;
|
|
28450
29563
|
if (!trimmedContent && !hasFiles)
|
|
28451
29564
|
return;
|
|
28452
|
-
|
|
29565
|
+
if (stateRef.current.isTyping) {
|
|
29566
|
+
console.warn('[Widget] Cannot send message while streaming is in progress');
|
|
29567
|
+
return;
|
|
29568
|
+
}
|
|
29569
|
+
if (abortControllerRef.current) {
|
|
29570
|
+
abortControllerRef.current.abort();
|
|
29571
|
+
abortControllerRef.current = null;
|
|
29572
|
+
}
|
|
29573
|
+
abortControllerRef.current = new AbortController();
|
|
28453
29574
|
const displayContent = trimmedContent.replace(/^\[EXECUTE_ACTION:[^\]]+\]\s*/, '');
|
|
28454
29575
|
const userMessage = {
|
|
28455
29576
|
id: generateMessageId(),
|
|
@@ -28460,12 +29581,11 @@ function useChat(options) {
|
|
|
28460
29581
|
timestamp: new Date().toISOString(),
|
|
28461
29582
|
sources: [],
|
|
28462
29583
|
};
|
|
28463
|
-
// Add user message immediately
|
|
28464
29584
|
setState(prev => ({
|
|
28465
29585
|
...prev,
|
|
28466
29586
|
messages: [...prev.messages, userMessage],
|
|
28467
|
-
isLoading: false,
|
|
28468
|
-
isTyping: true,
|
|
29587
|
+
isLoading: false,
|
|
29588
|
+
isTyping: true,
|
|
28469
29589
|
error: null,
|
|
28470
29590
|
}));
|
|
28471
29591
|
onMessage?.(userMessage);
|
|
@@ -28505,16 +29625,29 @@ function useChat(options) {
|
|
|
28505
29625
|
}
|
|
28506
29626
|
catch (uploadError) {
|
|
28507
29627
|
console.error('Failed to upload file:', uploadError);
|
|
28508
|
-
// Continue with other files
|
|
28509
29628
|
}
|
|
28510
29629
|
}
|
|
28511
29630
|
}
|
|
28512
|
-
// Stream the response
|
|
28513
29631
|
let lastStreamedMessage = null;
|
|
28514
29632
|
const streamState = createStreamState();
|
|
28515
|
-
|
|
29633
|
+
currentRequestIdRef.current = streamState.requestId;
|
|
29634
|
+
const currentAbortController = abortControllerRef.current;
|
|
29635
|
+
const streamConversationId = conversationId;
|
|
29636
|
+
const streamRequestId = streamState.requestId;
|
|
29637
|
+
const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds, currentAbortController?.signal);
|
|
28516
29638
|
for await (const event of stream) {
|
|
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');
|
|
29643
|
+
break;
|
|
29644
|
+
}
|
|
28517
29645
|
if (event.type === "action_request") {
|
|
29646
|
+
if (currentAbortController?.signal.aborted ||
|
|
29647
|
+
stateRef.current.conversationId !== streamConversationId ||
|
|
29648
|
+
currentRequestIdRef.current !== streamRequestId) {
|
|
29649
|
+
break;
|
|
29650
|
+
}
|
|
28518
29651
|
await handleActionLoop(apiClient.current, event, streamState, (message) => {
|
|
28519
29652
|
lastStreamedMessage = message;
|
|
28520
29653
|
}, setState, widgetId, conversationId, () => stateRef.current.messages);
|
|
@@ -28524,25 +29657,26 @@ function useChat(options) {
|
|
|
28524
29657
|
lastStreamedMessage = message;
|
|
28525
29658
|
}, setState);
|
|
28526
29659
|
}
|
|
28527
|
-
|
|
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');
|
|
29664
|
+
return;
|
|
29665
|
+
}
|
|
28528
29666
|
setState(prev => ({
|
|
28529
29667
|
...prev,
|
|
28530
29668
|
isLoading: false,
|
|
28531
29669
|
isTyping: false,
|
|
28532
29670
|
}));
|
|
28533
|
-
// Notify about final message
|
|
28534
29671
|
if (lastStreamedMessage) {
|
|
28535
29672
|
onMessage?.(lastStreamedMessage);
|
|
28536
29673
|
}
|
|
28537
|
-
// Generate follow-up suggestions asynchronously
|
|
28538
29674
|
const enableFollowUps = state.config?.settings.enableFollowUpSuggestions !== false;
|
|
28539
29675
|
const actionIds = state.config?.actions || [];
|
|
28540
29676
|
if (enableFollowUps) {
|
|
28541
|
-
// Don't await - let it run in background
|
|
28542
29677
|
apiClient.current.generateFollowUps(stateRef.current.messages, actionIds)
|
|
28543
29678
|
.then(suggestions => {
|
|
28544
29679
|
if (suggestions.length > 0) {
|
|
28545
|
-
// Attach suggestions to the last assistant message
|
|
28546
29680
|
setState(prev => {
|
|
28547
29681
|
const messages = [...prev.messages];
|
|
28548
29682
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -28571,7 +29705,7 @@ function useChat(options) {
|
|
|
28571
29705
|
},
|
|
28572
29706
|
timestamp: new Date().toISOString(),
|
|
28573
29707
|
sources: [],
|
|
28574
|
-
isError: !fallbackMessage,
|
|
29708
|
+
isError: !fallbackMessage,
|
|
28575
29709
|
};
|
|
28576
29710
|
setState(prev => ({
|
|
28577
29711
|
...prev,
|
|
@@ -28583,9 +29717,6 @@ function useChat(options) {
|
|
|
28583
29717
|
onError?.(err);
|
|
28584
29718
|
}
|
|
28585
29719
|
}, [state.conversationId, state.config, state.messages, onMessage, onError]);
|
|
28586
|
-
/**
|
|
28587
|
-
* Clear all messages
|
|
28588
|
-
*/
|
|
28589
29720
|
const clearMessages = React.useCallback(() => {
|
|
28590
29721
|
setState(prev => ({
|
|
28591
29722
|
...prev,
|
|
@@ -28598,9 +29729,6 @@ function useChat(options) {
|
|
|
28598
29729
|
clearConversation(widgetId);
|
|
28599
29730
|
}
|
|
28600
29731
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
28601
|
-
/**
|
|
28602
|
-
* Submit feedback for a message
|
|
28603
|
-
*/
|
|
28604
29732
|
const submitFeedback = React.useCallback(async (messageId, feedback) => {
|
|
28605
29733
|
try {
|
|
28606
29734
|
const message = state.messages.find(msg => msg.id === messageId);
|
|
@@ -28610,7 +29738,6 @@ function useChat(options) {
|
|
|
28610
29738
|
: undefined;
|
|
28611
29739
|
console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
|
|
28612
29740
|
await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
|
|
28613
|
-
// Update message with feedback
|
|
28614
29741
|
setState(prev => ({
|
|
28615
29742
|
...prev,
|
|
28616
29743
|
messages: prev.messages.map(msg => msg.id === messageId
|
|
@@ -28625,9 +29752,6 @@ function useChat(options) {
|
|
|
28625
29752
|
onError?.(err);
|
|
28626
29753
|
}
|
|
28627
29754
|
}, [state.conversationId, onError]);
|
|
28628
|
-
/**
|
|
28629
|
-
* Load conversation history list from localStorage
|
|
28630
|
-
*/
|
|
28631
29755
|
const loadConversations = React.useCallback(() => {
|
|
28632
29756
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
28633
29757
|
if (!persistConversation || !isStorageAvailable()) {
|
|
@@ -28644,8 +29768,11 @@ function useChat(options) {
|
|
|
28644
29768
|
})));
|
|
28645
29769
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
28646
29770
|
const switchConversation = React.useCallback(async (conversationId) => {
|
|
29771
|
+
if (abortControllerRef.current) {
|
|
29772
|
+
abortControllerRef.current.abort();
|
|
29773
|
+
abortControllerRef.current = null;
|
|
29774
|
+
}
|
|
28647
29775
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
28648
|
-
// First try to load from localStorage
|
|
28649
29776
|
if (persistConversation && isStorageAvailable()) {
|
|
28650
29777
|
const stored = loadConversationById(widgetId, conversationId);
|
|
28651
29778
|
if (stored) {
|
|
@@ -28653,16 +29780,17 @@ function useChat(options) {
|
|
|
28653
29780
|
...prev,
|
|
28654
29781
|
conversationId: stored.conversationId,
|
|
28655
29782
|
messages: hydrateMessages(stored.messages),
|
|
29783
|
+
isTyping: false,
|
|
29784
|
+
isLoading: false,
|
|
28656
29785
|
}));
|
|
28657
29786
|
setActiveConversation(widgetId, conversationId);
|
|
28658
29787
|
return;
|
|
28659
29788
|
}
|
|
28660
29789
|
}
|
|
28661
|
-
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
29790
|
+
setState(prev => ({ ...prev, isLoading: true, isTyping: false, error: null }));
|
|
28662
29791
|
try {
|
|
28663
29792
|
const conversation = await apiClient.current.getOrCreateConversation(conversationId);
|
|
28664
29793
|
const hydratedMessages = hydrateMessages(conversation.messages);
|
|
28665
|
-
// Clear old resume callbacks
|
|
28666
29794
|
state.messages.forEach(message => {
|
|
28667
29795
|
if (message.action?.toolCallId) {
|
|
28668
29796
|
unregisterActionResumeCallback(message.action.toolCallId);
|
|
@@ -28674,9 +29802,7 @@ function useChat(options) {
|
|
|
28674
29802
|
messages: hydratedMessages,
|
|
28675
29803
|
isLoading: false,
|
|
28676
29804
|
}));
|
|
28677
|
-
|
|
28678
|
-
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
|
|
28679
|
-
// Save to local storage
|
|
29805
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }), createStreamState, registerActionResumeCallback);
|
|
28680
29806
|
if (persistConversation && isStorageAvailable()) {
|
|
28681
29807
|
saveConversation(widgetId, conversation.id, hydratedMessages);
|
|
28682
29808
|
}
|
|
@@ -28687,11 +29813,23 @@ function useChat(options) {
|
|
|
28687
29813
|
}
|
|
28688
29814
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
28689
29815
|
const startNewConversation = React.useCallback(() => {
|
|
29816
|
+
const now = Date.now();
|
|
29817
|
+
if (now - lastNewChatTimeRef.current < NEW_CHAT_COOLDOWN_MS) {
|
|
29818
|
+
console.warn('[Widget] New chat rate limited - please wait');
|
|
29819
|
+
return;
|
|
29820
|
+
}
|
|
29821
|
+
lastNewChatTimeRef.current = now;
|
|
29822
|
+
if (abortControllerRef.current) {
|
|
29823
|
+
abortControllerRef.current.abort();
|
|
29824
|
+
abortControllerRef.current = null;
|
|
29825
|
+
}
|
|
28690
29826
|
setState(prev => ({
|
|
28691
29827
|
...prev,
|
|
28692
29828
|
messages: [],
|
|
28693
29829
|
conversationId: '',
|
|
28694
29830
|
error: null,
|
|
29831
|
+
isTyping: false,
|
|
29832
|
+
isLoading: false,
|
|
28695
29833
|
}));
|
|
28696
29834
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
28697
29835
|
if (persistConversation && isStorageAvailable()) {
|
|
@@ -28703,11 +29841,8 @@ function useChat(options) {
|
|
|
28703
29841
|
if (!persistConversation || !isStorageAvailable()) {
|
|
28704
29842
|
return;
|
|
28705
29843
|
}
|
|
28706
|
-
// Delete from storage
|
|
28707
29844
|
deleteConversation(widgetId, conversationId);
|
|
28708
|
-
// Update local state
|
|
28709
29845
|
setConversations(prev => prev.filter(c => c.id !== conversationId));
|
|
28710
|
-
// If we deleted the current conversation, clear it
|
|
28711
29846
|
if (state.conversationId === conversationId) {
|
|
28712
29847
|
setState(prev => ({
|
|
28713
29848
|
...prev,
|
|
@@ -28727,7 +29862,6 @@ function useChat(options) {
|
|
|
28727
29862
|
sendMessage,
|
|
28728
29863
|
clearMessages,
|
|
28729
29864
|
submitFeedback,
|
|
28730
|
-
// Chat history features
|
|
28731
29865
|
conversations,
|
|
28732
29866
|
loadConversations,
|
|
28733
29867
|
switchConversation,
|
|
@@ -28736,11 +29870,20 @@ function useChat(options) {
|
|
|
28736
29870
|
};
|
|
28737
29871
|
}
|
|
28738
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
|
+
|
|
28739
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" })] }));
|
|
28740
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" })] }));
|
|
28741
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" })] }));
|
|
28742
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" })] }));
|
|
28743
|
-
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,
|
|
28744
29887
|
// Chat history props (only active when persistConversation is true)
|
|
28745
29888
|
conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
|
|
28746
29889
|
// Override props for live preview
|
|
@@ -28757,6 +29900,8 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
|
|
|
28757
29900
|
const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
|
|
28758
29901
|
// Track if history panel is open
|
|
28759
29902
|
const [showHistory, setShowHistory] = React.useState(false);
|
|
29903
|
+
// Track if data policy view is open
|
|
29904
|
+
const [showDataPolicy, setShowDataPolicy] = React.useState(false);
|
|
28760
29905
|
// Scroll button state (managed by MessageList)
|
|
28761
29906
|
const [showScrollButton, setShowScrollButton] = React.useState(false);
|
|
28762
29907
|
const [scrollToBottom, setScrollToBottom] = React.useState(null);
|
|
@@ -28766,6 +29911,13 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
|
|
|
28766
29911
|
}, []);
|
|
28767
29912
|
// History exit animation when starting a new chat from overview
|
|
28768
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
|
+
}, []);
|
|
28769
29921
|
// Load conversations when history panel opens
|
|
28770
29922
|
const handleOpenHistory = () => {
|
|
28771
29923
|
setShowHistory(true);
|
|
@@ -28813,10 +29965,22 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
|
|
|
28813
29965
|
// The backend will detect and trigger the action based on the message
|
|
28814
29966
|
onSendMessage(question);
|
|
28815
29967
|
};
|
|
28816
|
-
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) => {
|
|
28817
29971
|
e.stopPropagation();
|
|
28818
29972
|
onDeleteConversation(conv.id);
|
|
28819
|
-
}, "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 })] }))] }));
|
|
28820
29984
|
};
|
|
28821
29985
|
|
|
28822
29986
|
/**
|
|
@@ -29222,7 +30386,7 @@ function styleInject(css, ref) {
|
|
|
29222
30386
|
if ( ref === void 0 ) ref = {};
|
|
29223
30387
|
var insertAt = ref.insertAt;
|
|
29224
30388
|
|
|
29225
|
-
if (typeof document === 'undefined') { return; }
|
|
30389
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
29226
30390
|
|
|
29227
30391
|
var head = document.head || document.getElementsByTagName('head')[0];
|
|
29228
30392
|
var style = document.createElement('style');
|
|
@@ -29245,7 +30409,10 @@ function styleInject(css, ref) {
|
|
|
29245
30409
|
}
|
|
29246
30410
|
}
|
|
29247
30411
|
|
|
29248
|
-
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-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{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{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-md) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items: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,44px);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,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,8px);color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:32px;justify-content:center;margin-left:auto;margin-right:var(--space-2xs,2px);opacity:0;transition:opacity var(--duration-fast,.15s) ease,background var(--duration-fast,.15s) ease,color var(--duration-fast,.15s) ease;width:32px}.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:#22c55e;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%}.ai-chat-sources{background:rgba(0,0,0,.02);border-radius:6px;font-size:var(--text-xs);margin-top:var(--space-sm);overflow:hidden}.ai-chat-sources-toggle{align-items:center;background:none;border:none;cursor:pointer;display:flex;gap:6px;padding:var(--space-sm) 10px;text-align:left;transition:background var(--duration-fast) ease;width:100%}.ai-chat-sources-toggle:hover{background:rgba(0,0,0,.03)}.ai-chat-sources-icon{color:var(--text-muted);font-size:10px;transition:transform var(--duration-fast) ease}.ai-chat-sources-title{color:var(--text-primary);flex:1;font-size:11px;font-weight:var(--font-weight-semibold);letter-spacing:.5px;text-transform:uppercase}.ai-chat-source-item{border-top:1px solid rgba(0,0,0,.05);color:var(--text-muted);display:flex;gap:var(--space-sm);padding:var(--space-sm) 10px}.ai-chat-source-item:last-child{border-bottom:none}.ai-chat-source-number{color:var(--btn-primary-bg);flex-shrink:0;font-weight:var(--font-weight-semibold)}.ai-chat-source-details{display:flex;flex:1;flex-direction:column;gap:var(--space-xs)}.ai-chat-source-score{color:var(--text-placeholder);font-size:11px}.ai-chat-source-content{color:var(--text-muted);font-size:11px;font-style:italic;line-height:var(--line-height-normal)}.ai-chat-source-metadata{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}.ai-chat-source-meta-item{background:rgba(0,0,0,.05);border-radius:3px;color:var(--text-muted);font-size:10px;padding:2px 6px}";
|
|
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}";
|
|
29249
30416
|
styleInject(css_248z);
|
|
29250
30417
|
|
|
29251
30418
|
// Icon components mapping
|
|
@@ -29253,9 +30420,10 @@ const iconComponents = {
|
|
|
29253
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" }) })),
|
|
29254
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" }) })),
|
|
29255
30422
|
};
|
|
29256
|
-
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', }) => {
|
|
29257
30424
|
const [isOpen, setIsOpen] = React.useState(defaultOpen);
|
|
29258
30425
|
const [autoDetectedTheme, setAutoDetectedTheme] = React.useState('light');
|
|
30426
|
+
const [showWelcomeBubble, setShowWelcomeBubble] = React.useState(false);
|
|
29259
30427
|
const widgetRef = React.useRef(null);
|
|
29260
30428
|
const containerRef = React.useRef(null);
|
|
29261
30429
|
// Determine mode
|
|
@@ -29277,10 +30445,9 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29277
30445
|
showChatHistory: true,
|
|
29278
30446
|
showTimestamps: true,
|
|
29279
30447
|
showTypingIndicator: true,
|
|
30448
|
+
showToolCalls: false,
|
|
29280
30449
|
enableFileUpload: false,
|
|
29281
30450
|
enableFeedback: true,
|
|
29282
|
-
showSources: false,
|
|
29283
|
-
sourceDisplayMode: 'none',
|
|
29284
30451
|
},
|
|
29285
30452
|
behavior: {
|
|
29286
30453
|
agentic: false,
|
|
@@ -29317,7 +30484,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29317
30484
|
const messages = previewMode ? [] : chatHook.messages;
|
|
29318
30485
|
const isLoading = previewMode ? false : chatHook.isLoading;
|
|
29319
30486
|
const isTyping = previewMode ? false : chatHook.isTyping;
|
|
29320
|
-
const error = previewMode ? null : chatHook.error;
|
|
29321
30487
|
const config = previewMode ? mergedPreviewConfig : chatHook.config;
|
|
29322
30488
|
const sendMessage = previewMode ? (() => Promise.resolve()) : chatHook.sendMessage;
|
|
29323
30489
|
const submitFeedback = previewMode ? (() => Promise.resolve()) : chatHook.submitFeedback;
|
|
@@ -29352,8 +30518,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29352
30518
|
mediaQuery.removeEventListener('change', handleMediaChange);
|
|
29353
30519
|
};
|
|
29354
30520
|
}, [config]);
|
|
29355
|
-
//
|
|
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)
|
|
29356
30524
|
React.useEffect(() => {
|
|
30525
|
+
// Never auto-open on mobile devices
|
|
30526
|
+
if (isMobile)
|
|
30527
|
+
return undefined;
|
|
29357
30528
|
if (!isEmbedded && config?.settings.autoOpen) {
|
|
29358
30529
|
const delay = config.settings.autoOpenDelay || 0;
|
|
29359
30530
|
const timer = setTimeout(() => {
|
|
@@ -29363,7 +30534,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29363
30534
|
return () => clearTimeout(timer);
|
|
29364
30535
|
}
|
|
29365
30536
|
return undefined;
|
|
29366
|
-
}, [config, onOpen, isEmbedded]);
|
|
30537
|
+
}, [config, onOpen, isEmbedded, isMobile]);
|
|
29367
30538
|
// Handle close on Escape key (only for bubble mode)
|
|
29368
30539
|
React.useEffect(() => {
|
|
29369
30540
|
if (!isOpen || isEmbedded)
|
|
@@ -29377,6 +30548,37 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29377
30548
|
document.addEventListener('keydown', handleEscapeKey);
|
|
29378
30549
|
return () => document.removeEventListener('keydown', handleEscapeKey);
|
|
29379
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]);
|
|
29380
30582
|
// Determine theme - use prop override if provided, otherwise auto-detect
|
|
29381
30583
|
const appearanceConfig = config?.appearance;
|
|
29382
30584
|
const effectiveTheme = theme ?? autoDetectedTheme;
|
|
@@ -29390,6 +30592,7 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29390
30592
|
const effectiveWelcomeTitle = welcomeTitle ?? appearanceConfig?.welcomeTitle ?? '';
|
|
29391
30593
|
const effectiveWelcomeMessage = welcomeMessage ?? appearanceConfig?.welcomeMessage ?? '';
|
|
29392
30594
|
const effectivePlaceholder = placeholder ?? appearanceConfig?.placeholder ?? '';
|
|
30595
|
+
const effectiveWelcomeBubbleText = welcomeBubbleText ?? appearanceConfig?.welcomeBubbleText ?? '';
|
|
29393
30596
|
// Generate styles using simplified theme system
|
|
29394
30597
|
const simpleAppearance = {
|
|
29395
30598
|
accentColor};
|
|
@@ -29411,6 +30614,18 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29411
30614
|
return;
|
|
29412
30615
|
const newState = !isOpen;
|
|
29413
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
|
+
}
|
|
29414
30629
|
if (newState) {
|
|
29415
30630
|
onOpen?.();
|
|
29416
30631
|
}
|
|
@@ -29441,13 +30656,13 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
|
|
|
29441
30656
|
const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
|
|
29442
30657
|
// Embedded mode renders directly without wrapper positioning
|
|
29443
30658
|
if (isEmbedded) {
|
|
29444
|
-
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 }) }));
|
|
29445
30660
|
}
|
|
29446
|
-
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,
|
|
29447
30662
|
// Chat history props (only active when persistConversation is true)
|
|
29448
30663
|
conversations: conversations, onLoadConversations: loadConversations, onSwitchConversation: switchConversation, onStartNewConversation: startNewConversation, onDeleteConversation: deleteConversation, currentConversationId: conversationId,
|
|
29449
30664
|
// Override props for live preview
|
|
29450
|
-
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, {}) }) })] }) }));
|
|
29451
30666
|
};
|
|
29452
30667
|
|
|
29453
30668
|
exports.ApiError = ApiError;
|