@chatwidgetai/chat-widget 0.2.3 → 0.2.4

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.
Files changed (34) hide show
  1. package/dist/actions/google-calendar-appointment/component.d.ts +6 -0
  2. package/dist/actions/google-calendar-appointment/component.d.ts.map +1 -0
  3. package/dist/actions/google-calendar-appointment/handler.d.ts +2 -0
  4. package/dist/actions/google-calendar-appointment/handler.d.ts.map +1 -0
  5. package/dist/actions/google-calendar-appointment/index.d.ts +3 -0
  6. package/dist/actions/google-calendar-appointment/index.d.ts.map +1 -0
  7. package/dist/actions/index.d.ts +3 -0
  8. package/dist/actions/index.d.ts.map +1 -0
  9. package/dist/actions/registry.d.ts +24 -0
  10. package/dist/actions/registry.d.ts.map +1 -0
  11. package/dist/ai-chat-widget.umd.js +803 -300
  12. package/dist/ai-chat-widget.umd.js.map +1 -1
  13. package/dist/api/client.d.ts +8 -20
  14. package/dist/api/client.d.ts.map +1 -1
  15. package/dist/components/ChatWidget.d.ts.map +1 -1
  16. package/dist/components/ChatWindow.d.ts.map +1 -1
  17. package/dist/components/Message.d.ts.map +1 -1
  18. package/dist/components/MessageList.d.ts.map +1 -1
  19. package/dist/components/ToolMessageGroup.d.ts.map +1 -1
  20. package/dist/hooks/useChat.d.ts.map +1 -1
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.esm.js +803 -300
  24. package/dist/index.esm.js.map +1 -1
  25. package/dist/index.js +803 -300
  26. package/dist/index.js.map +1 -1
  27. package/dist/types/index.d.ts +86 -40
  28. package/dist/types/index.d.ts.map +1 -1
  29. package/dist/umd.d.ts +2 -1
  30. package/dist/umd.d.ts.map +1 -1
  31. package/dist/utils/sse-parser.d.ts +2 -0
  32. package/dist/utils/sse-parser.d.ts.map +1 -0
  33. package/dist/utils/storage.d.ts.map +1 -1
  34. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3,6 +3,53 @@
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
4
  var react = require('react');
5
5
 
6
+ async function* parseSSEStream(response, validator) {
7
+ if (!response.body) {
8
+ throw new Error("Response body is null");
9
+ }
10
+ const reader = response.body.getReader();
11
+ const decoder = new TextDecoder();
12
+ let buffer = "";
13
+ try {
14
+ while (true) {
15
+ const { done, value } = await reader.read();
16
+ if (done)
17
+ break;
18
+ buffer += decoder.decode(value, { stream: true });
19
+ const chunks = buffer.split("\n\n");
20
+ buffer = chunks.pop() || "";
21
+ for (const chunk of chunks) {
22
+ const lines = chunk.split("\n");
23
+ for (const line of lines) {
24
+ if (line.startsWith("data: ")) {
25
+ try {
26
+ const data = JSON.parse(line.slice(6));
27
+ if (validator) {
28
+ if (validator(data)) {
29
+ yield data;
30
+ }
31
+ else {
32
+ console.warn("[SSE Parser] Data failed validation:", data);
33
+ }
34
+ }
35
+ else {
36
+ yield data;
37
+ }
38
+ }
39
+ catch (e) {
40
+ console.error("[SSE Parser] Failed to parse SSE data:", line, e);
41
+ throw e;
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
48
+ finally {
49
+ reader.releaseLock();
50
+ }
51
+ }
52
+
6
53
  /**
7
54
  * API Client for Widget Communication
8
55
  * Handles all HTTP requests to the widget API
@@ -138,12 +185,8 @@ class WidgetApiClient {
138
185
  const result = await response.json();
139
186
  return result.file;
140
187
  }
141
- /**
142
- * Send a chat message (standard RAG, no actions)
143
- * Returns ConversationMessage[] array
144
- */
145
- async sendMessage(conversationId, message, fileIds) {
146
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/chat`, {
188
+ async *sendAgentMessageStream(conversationId, message, fileIds) {
189
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
147
190
  method: 'POST',
148
191
  headers: {
149
192
  'Content-Type': 'application/json',
@@ -156,167 +199,36 @@ class WidgetApiClient {
156
199
  }),
157
200
  });
158
201
  if (!response.ok) {
159
- throw await buildApiError(response, 'Failed to send message');
160
- }
161
- return response.json();
162
- }
163
- /**
164
- * Send a message to agent (with actions support)
165
- */
166
- async sendAgentMessage(conversationId, message, fileIds) {
167
- try {
168
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
169
- method: 'POST',
170
- headers: {
171
- 'Content-Type': 'application/json',
172
- },
173
- body: JSON.stringify({
174
- conversationId: conversationId,
175
- message,
176
- fileIds,
177
- timeZone: this.getTimeZone(),
178
- }),
179
- });
180
- if (!response.ok) {
181
- throw await buildApiError(response, `Agent request failed with status ${response.status}`);
182
- }
183
- const data = await response.json();
184
- // Check if response indicates an error
185
- if (data.type === 'error') {
186
- throw new Error(data.message || 'Agent encountered an error');
187
- }
188
- return data;
189
- }
190
- catch (error) {
191
- // Enhance error messages
192
- if (error instanceof TypeError && error.message.includes('fetch')) {
193
- throw new ApiError('Network error: Unable to reach the server', 0);
194
- }
195
- throw error;
202
+ throw await buildApiError(response, 'Failed to send agent message');
196
203
  }
197
- }
198
- /**
199
- * Stream chat message responses
200
- */
201
- async *sendMessageStream(conversationId, message, fileIds) {
202
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/chat`, {
203
- method: 'POST',
204
- headers: {
205
- 'Content-Type': 'application/json',
206
- },
207
- body: JSON.stringify({
208
- conversationId: conversationId,
209
- message,
210
- fileIds,
211
- timeZone: this.getTimeZone(),
212
- }),
204
+ yield* parseSSEStream(response, (data) => {
205
+ return typeof data === 'object' && data !== null && 'type' in data;
213
206
  });
214
- if (!response.ok) {
215
- throw await buildApiError(response, 'Failed to send message');
216
- }
217
- if (!response.body) {
218
- throw new Error('Response body is null');
219
- }
220
- const reader = response.body.getReader();
221
- const decoder = new TextDecoder();
222
- let buffer = '';
223
- try {
224
- while (true) {
225
- const { done, value } = await reader.read();
226
- if (done)
227
- break;
228
- buffer += decoder.decode(value, { stream: true });
229
- const lines = buffer.split('\n');
230
- buffer = lines.pop() || '';
231
- for (const line of lines) {
232
- if (line.startsWith('data: ')) {
233
- try {
234
- const data = JSON.parse(line.slice(6));
235
- // Handle error events
236
- if (data.type === 'error') {
237
- throw new Error(data.error || 'Stream error');
238
- }
239
- // Yield ConversationMessage objects
240
- if (data.id) {
241
- yield data;
242
- }
243
- }
244
- catch (e) {
245
- console.error('[Widget API Client] Failed to parse SSE data:', line, e);
246
- throw e;
247
- }
248
- }
249
- }
250
- }
251
- }
252
- finally {
253
- reader.releaseLock();
254
- }
255
207
  }
256
- /**
257
- * Stream agent message responses with tool execution
258
- * Handles streaming events from backend and yields ConversationMessage updates
259
- */
260
- async *sendAgentMessageStream(conversationId, message, fileIds) {
261
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
208
+ async *continueAgentMessageStream(conversationId, toolCallId, state) {
209
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
262
210
  method: 'POST',
263
211
  headers: {
264
212
  'Content-Type': 'application/json',
265
213
  },
266
214
  body: JSON.stringify({
267
215
  conversationId: conversationId,
268
- message,
269
- fileIds,
216
+ toolCallId,
217
+ state,
270
218
  timeZone: this.getTimeZone(),
271
219
  }),
272
220
  });
273
221
  if (!response.ok) {
274
- throw await buildApiError(response, 'Failed to send agent message');
275
- }
276
- if (!response.body) {
277
- throw new Error('Response body is null');
278
- }
279
- const reader = response.body.getReader();
280
- const decoder = new TextDecoder();
281
- let buffer = '';
282
- try {
283
- while (true) {
284
- const { done, value } = await reader.read();
285
- if (done)
286
- break;
287
- buffer += decoder.decode(value, { stream: true });
288
- const lines = buffer.split('\n');
289
- buffer = lines.pop() || '';
290
- for (const line of lines) {
291
- if (line.startsWith('data: ')) {
292
- try {
293
- const data = JSON.parse(line.slice(6));
294
- // Handle error events
295
- if (data.type === 'error') {
296
- throw new Error(data.error || 'Stream error');
297
- }
298
- // Yield ConversationMessage objects that come from the backend
299
- // The backend yields full ConversationMessage objects during streaming
300
- if (data.id) {
301
- yield data;
302
- }
303
- }
304
- catch (e) {
305
- console.error('[Widget API Client] Failed to parse SSE data:', line, e);
306
- throw e;
307
- }
308
- }
309
- }
310
- }
311
- }
312
- finally {
313
- reader.releaseLock();
222
+ throw await buildApiError(response, 'Failed to continue agent');
314
223
  }
224
+ yield* parseSSEStream(response, (data) => {
225
+ return typeof data === 'object' && data !== null && 'type' in data;
226
+ });
315
227
  }
316
228
  /**
317
229
  * Submit feedback for a message
318
230
  */
319
- async submitFeedback(sessionId, messageId, feedback) {
231
+ async submitFeedback(sessionId, messageId, feedback, meta) {
320
232
  const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/feedback`, {
321
233
  method: 'POST',
322
234
  headers: {
@@ -326,6 +238,9 @@ class WidgetApiClient {
326
238
  conversationId: sessionId,
327
239
  messageId: messageId,
328
240
  feedback,
241
+ messageRole: meta?.role,
242
+ messageContent: meta?.content,
243
+ messageTimestamp: meta?.timestamp,
329
244
  }),
330
245
  });
331
246
  if (!response.ok) {
@@ -376,6 +291,173 @@ function generateMessageId() {
376
291
  return `msg_${timestamp}_${randomStr}`;
377
292
  }
378
293
 
294
+ const pendingResolvers = new Map();
295
+ const resumeCallbacks = new Map();
296
+ const frontendActionHandlers = {};
297
+ const actionRenderers = {};
298
+ function getFrontendActionHandler(implementation) {
299
+ return frontendActionHandlers[implementation];
300
+ }
301
+ function getActionRenderer(implementation) {
302
+ return actionRenderers[implementation];
303
+ }
304
+ function getActionPrompt(implementation) {
305
+ if (implementation === "google-calendar-appointment") {
306
+ return "Select a date to continue.";
307
+ }
308
+ return "Action input required.";
309
+ }
310
+ function waitForActionState(toolCallId) {
311
+ return new Promise((resolve) => {
312
+ pendingResolvers.set(toolCallId, resolve);
313
+ });
314
+ }
315
+ function resolveActionState(toolCallId, state) {
316
+ const resolver = pendingResolvers.get(toolCallId);
317
+ if (resolver) {
318
+ pendingResolvers.delete(toolCallId);
319
+ resolver(state);
320
+ return;
321
+ }
322
+ // If no active resolver, check for a resume callback (for page reload scenario)
323
+ const resumeCallback = resumeCallbacks.get(toolCallId);
324
+ if (resumeCallback) {
325
+ resumeCallback(state).catch((error) => {
326
+ console.error("[Action] Failed to resume action:", error);
327
+ });
328
+ }
329
+ }
330
+ function registerActionResumeCallback(toolCallId, callback) {
331
+ resumeCallbacks.set(toolCallId, callback);
332
+ }
333
+ function unregisterActionResumeCallback(toolCallId) {
334
+ resumeCallbacks.delete(toolCallId);
335
+ }
336
+
337
+ function groupSlotsByDate(slots) {
338
+ const grouped = new Map();
339
+ for (const slot of slots) {
340
+ if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
341
+ continue;
342
+ }
343
+ const date = slot.startTime.slice(0, 10);
344
+ if (!grouped.has(date)) {
345
+ grouped.set(date, []);
346
+ }
347
+ grouped.get(date).push(slot);
348
+ }
349
+ return grouped;
350
+ }
351
+ function formatDate(dateStr) {
352
+ try {
353
+ const date = new Date(dateStr);
354
+ return new Intl.DateTimeFormat("en-US", {
355
+ weekday: "short",
356
+ month: "short",
357
+ day: "numeric",
358
+ }).format(date);
359
+ }
360
+ catch {
361
+ return dateStr;
362
+ }
363
+ }
364
+ function GoogleCalendarAppointmentCard({ message }) {
365
+ const action = message.action;
366
+ if (!action || action.implementation !== "google-calendar-appointment") {
367
+ return null;
368
+ }
369
+ const rawSlots = action.state.availableSlots;
370
+ const availableSlots = Array.isArray(rawSlots)
371
+ ? rawSlots.filter((slot) => slot !== null &&
372
+ slot !== undefined &&
373
+ typeof slot === "object" &&
374
+ "startTime" in slot &&
375
+ "endTime" in slot &&
376
+ typeof slot.startTime === "string" &&
377
+ typeof slot.endTime === "string")
378
+ : [];
379
+ const allowTopic = action.state.allowTopic !== false;
380
+ const isBooked = action.state.status === "booked";
381
+ const slotsByDate = groupSlotsByDate(availableSlots);
382
+ const dates = Array.from(slotsByDate.keys()).sort();
383
+ const [selectedDate, setSelectedDate] = react.useState(dates[0] ?? "");
384
+ const [selectedSlot, setSelectedSlot] = react.useState(null);
385
+ const [topic, setTopic] = react.useState("");
386
+ const [error, setError] = react.useState(null);
387
+ const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
388
+ const onConfirm = () => {
389
+ if (!selectedSlot) {
390
+ setError("Please select a time slot.");
391
+ return;
392
+ }
393
+ if (allowTopic && !topic.trim()) {
394
+ setError("Please enter a topic for the meeting.");
395
+ return;
396
+ }
397
+ setError(null);
398
+ resolveActionState(action.toolCallId, {
399
+ ...action.state,
400
+ selectedSlot: {
401
+ startTime: selectedSlot.startTime,
402
+ endTime: selectedSlot.endTime,
403
+ },
404
+ topic: allowTopic ? topic.trim() : null,
405
+ });
406
+ };
407
+ if (isBooked) {
408
+ const rawBookedSlot = action.state.selectedSlot;
409
+ const bookedSlot = rawBookedSlot &&
410
+ typeof rawBookedSlot === "object" &&
411
+ "startTime" in rawBookedSlot &&
412
+ "endTime" in rawBookedSlot
413
+ ? rawBookedSlot
414
+ : null;
415
+ const bookedTopic = typeof action.state.topic === "string" ? action.state.topic : null;
416
+ const eventLink = typeof action.state.bookedEventLink === "string" ? action.state.bookedEventLink : null;
417
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-action-card ai-chat-action-booked", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntime.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntime.jsx("path", { fillRule: "evenodd", d: "M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z", clipRule: "evenodd" }) }), "Appointment Confirmed"] }), jsxRuntime.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntime.jsxs("div", { className: "ai-chat-action-detail", children: [jsxRuntime.jsx("span", { className: "ai-chat-action-label", children: "Topic:" }), jsxRuntime.jsx("span", { className: "ai-chat-action-value", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntime.jsxs("div", { className: "ai-chat-action-detail", children: [jsxRuntime.jsx("span", { className: "ai-chat-action-label", children: "Time:" }), jsxRuntime.jsx("span", { className: "ai-chat-action-value", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxRuntime.jsx("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link", children: "View in Google Calendar \u2192" }))] })] }));
418
+ }
419
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-action-card", children: [jsxRuntime.jsxs("div", { className: "ai-chat-action-header", children: [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" }) }), "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: () => {
420
+ setSelectedDate(date);
421
+ setSelectedSlot(null);
422
+ }, 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))) })] })), 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." }))] })] }));
423
+ }
424
+
425
+ frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
426
+ return waitForActionState(context.toolCallId);
427
+ };
428
+
429
+ function styleInject(css, ref) {
430
+ if ( ref === void 0 ) ref = {};
431
+ var insertAt = ref.insertAt;
432
+
433
+ if (!css || typeof document === 'undefined') { return; }
434
+
435
+ var head = document.head || document.getElementsByTagName('head')[0];
436
+ var style = document.createElement('style');
437
+ style.type = 'text/css';
438
+
439
+ if (insertAt === 'top') {
440
+ if (head.firstChild) {
441
+ head.insertBefore(style, head.firstChild);
442
+ } else {
443
+ head.appendChild(style);
444
+ }
445
+ } else {
446
+ head.appendChild(style);
447
+ }
448
+
449
+ if (style.styleSheet) {
450
+ style.styleSheet.cssText = css;
451
+ } else {
452
+ style.appendChild(document.createTextNode(css));
453
+ }
454
+ }
455
+
456
+ var css_248z$1 = ".ai-chat-action-card{background:linear-gradient(135deg,#fff,#f9fafb);border:1px solid #e5e7eb;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.06);margin-top:12px;padding:20px;transition:all .2s ease}.ai-chat-action-card:hover{box-shadow:0 4px 12px rgba(0,0,0,.1)}.ai-chat-action-booked{background:linear-gradient(135deg,#ecfdf5,#d1fae5);border-color:#10b981}.ai-chat-action-header{align-items:center;color:#111827;display:flex;font-size:16px;font-weight:600;gap:8px;margin-bottom:16px}.ai-chat-action-icon{color:#6366f1;height:20px;width:20px}.ai-chat-action-icon-success{color:#10b981;height:24px;width:24px}.ai-chat-action-body{display:flex;flex-direction:column;gap:16px}.ai-chat-action-field{display:flex;flex-direction:column;gap:8px}.ai-chat-action-label{color:#374151;font-size:13px;font-weight:500}.ai-chat-action-input{background:#fff;border:1px solid #d1d5db;border-radius:8px;font-size:14px;padding:10px 12px;transition:all .2s ease}.ai-chat-action-input:focus{border-color:#6366f1;box-shadow:0 0 0 3px rgba(99,102,241,.1);outline:none}.ai-chat-action-date-grid{display:grid;gap:8px;grid-template-columns:repeat(auto-fill,minmax(110px,1fr))}.ai-chat-action-date-btn{background:#fff;border:1px solid #d1d5db;border-radius:8px;color:#374151;cursor:pointer;font-size:13px;font-weight:500;padding:10px 8px;transition:all .2s ease}.ai-chat-action-date-btn:hover{background:#f3f4f6;border-color:#9ca3af}.ai-chat-action-date-btn.active{background:#6366f1;border-color:#6366f1;color:#fff}.ai-chat-action-time-grid{display:grid;gap:8px;grid-template-columns:repeat(auto-fill,minmax(100px,1fr))}.ai-chat-action-time-btn{background:#fff;border:1px solid #d1d5db;border-radius:8px;color:#374151;cursor:pointer;font-size:13px;font-weight:500;padding:10px 8px;transition:all .2s ease}.ai-chat-action-time-btn:hover{background:#f3f4f6;border-color:#9ca3af}.ai-chat-action-time-btn.active{background:#6366f1;border-color:#6366f1;color:#fff}.ai-chat-action-button{background:linear-gradient(135deg,#6366f1,#4f46e5);border:none;border-radius:8px;box-shadow:0 2px 4px rgba(99,102,241,.2);color:#fff;cursor:pointer;font-size:14px;font-weight:600;padding:12px 20px;transition:all .2s ease}.ai-chat-action-button:hover:not(:disabled){background:linear-gradient(135deg,#4f46e5,#4338ca);box-shadow:0 4px 8px rgba(99,102,241,.3);transform:translateY(-1px)}.ai-chat-action-button:disabled{cursor:not-allowed;opacity:.5;transform:none}.ai-chat-action-error{background:#fef2f2;border:1px solid #fecaca;border-radius:8px;color:#dc2626;font-size:13px;font-weight:500;padding:10px 12px}.ai-chat-action-hint{color:#6b7280;font-size:12px;font-style:italic}.ai-chat-action-detail{background:#fff;border:1px solid #e5e7eb;border-radius:8px;display:flex;flex-direction:column;gap:4px;padding:12px}.ai-chat-action-detail .ai-chat-action-label{color:#6b7280;font-size:12px;letter-spacing:.5px;text-transform:uppercase}.ai-chat-action-detail .ai-chat-action-value{color:#111827;font-size:14px;font-weight:600}.ai-chat-action-link{align-items:center;background:#fff;border:1px solid #10b981;border-radius:8px;color:#10b981;display:inline-flex;font-size:14px;font-weight:600;gap:4px;padding:10px 16px;text-decoration:none;transition:all .2s ease}.ai-chat-action-link:hover{background:#10b981;color:#fff;transform:translateX(2px)}";
457
+ styleInject(css_248z$1);
458
+
459
+ actionRenderers["google-calendar-appointment"] = (message) => (jsxRuntime.jsx(GoogleCalendarAppointmentCard, { message: message }));
460
+
379
461
  /**
380
462
  * Local Storage Utilities
381
463
  * Handles conversation persistence in browser localStorage
@@ -437,9 +519,12 @@ function setWidgetStorage(widgetId, storage) {
437
519
  * Get preview text from messages
438
520
  */
439
521
  function getConversationPreview(messages) {
440
- const firstUserMessage = messages.find(m => m.message.type === 'human');
522
+ const firstUserMessage = messages.find(m => m.message.role === "user");
441
523
  if (firstUserMessage) {
442
- return firstUserMessage.message.content.slice(0, 100);
524
+ const content = typeof firstUserMessage.message.content === "string"
525
+ ? firstUserMessage.message.content
526
+ : "";
527
+ return content.slice(0, 100);
443
528
  }
444
529
  return 'New conversation';
445
530
  }
@@ -594,6 +679,473 @@ function isStorageAvailable() {
594
679
  * useChat Hook
595
680
  * Main state management for chat functionality
596
681
  */
682
+ function hydrateToolNames(messages) {
683
+ const toolCallNameById = new Map();
684
+ for (const entry of messages) {
685
+ if (entry.message.role !== "assistant") {
686
+ continue;
687
+ }
688
+ const toolCalls = entry.message.tool_calls;
689
+ if (!Array.isArray(toolCalls)) {
690
+ continue;
691
+ }
692
+ for (const call of toolCalls) {
693
+ const callId = call?.id;
694
+ const callName = call?.function?.name;
695
+ if (callId && callName) {
696
+ toolCallNameById.set(callId, callName);
697
+ }
698
+ }
699
+ }
700
+ if (toolCallNameById.size === 0) {
701
+ return messages;
702
+ }
703
+ return messages.map((entry) => {
704
+ if (entry.message.role !== "tool") {
705
+ return entry;
706
+ }
707
+ const toolCallId = entry.message.tool_call_id;
708
+ const resolvedName = toolCallNameById.get(toolCallId);
709
+ if (!resolvedName) {
710
+ return entry;
711
+ }
712
+ const currentName = entry.message.name;
713
+ const nextName = currentName && currentName.trim().length > 0 ? currentName : resolvedName;
714
+ const nextToolExecuting = entry.toolExecuting || resolvedName;
715
+ if (nextName === currentName && nextToolExecuting === entry.toolExecuting) {
716
+ return entry;
717
+ }
718
+ return {
719
+ ...entry,
720
+ message: { ...entry.message, name: nextName },
721
+ toolExecuting: nextToolExecuting,
722
+ };
723
+ });
724
+ }
725
+ function hydrateActionContent(messages) {
726
+ return messages.map((entry) => {
727
+ if (entry.message.role !== "assistant" || !entry.action) {
728
+ return entry;
729
+ }
730
+ const content = typeof entry.message.content === "string" ? entry.message.content : "";
731
+ if (content.trim().length > 0) {
732
+ return entry;
733
+ }
734
+ return {
735
+ ...entry,
736
+ message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
737
+ };
738
+ });
739
+ }
740
+ function hydrateMessages(messages) {
741
+ return hydrateActionContent(hydrateToolNames(messages));
742
+ }
743
+ function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
744
+ // Find all incomplete actions and register resume callbacks
745
+ for (const message of messages) {
746
+ if (message.action && !message.action.done) {
747
+ const toolCallId = message.action.toolCallId;
748
+ const toolName = message.message.name || message.toolExecuting || "tool";
749
+ registerActionResumeCallback(toolCallId, async (newState) => {
750
+ // When user interacts with the action after reload, continue the stream
751
+ try {
752
+ // Update the action message with the new state
753
+ setState(prev => ({
754
+ ...prev,
755
+ messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
756
+ ? {
757
+ ...m,
758
+ action: m.action ? { ...m.action, state: newState } : undefined,
759
+ }
760
+ : m),
761
+ isTyping: true,
762
+ }));
763
+ const streamState = createStreamState();
764
+ // Continue the agent stream with the new state
765
+ for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
766
+ if (event.type === "done") {
767
+ finalizeToolMessage(streamState, setState, toolCallId, toolName);
768
+ streamState.sources = event.sources;
769
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
770
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
771
+ continue;
772
+ }
773
+ if (event.type === "error") {
774
+ const errorMessage = {
775
+ id: generateMessageId(),
776
+ message: {
777
+ role: "assistant",
778
+ content: `Error: ${event.error}`,
779
+ },
780
+ timestamp: new Date().toISOString(),
781
+ sources: [],
782
+ isError: true,
783
+ };
784
+ upsertMessage(setState, errorMessage, false);
785
+ setState(prev => ({ ...prev, isTyping: false }));
786
+ return;
787
+ }
788
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
789
+ }
790
+ setState(prev => ({ ...prev, isTyping: false }));
791
+ }
792
+ catch (error) {
793
+ console.error("[Action Resume] Failed to continue stream:", error);
794
+ setState(prev => ({ ...prev, isTyping: false, error: error instanceof Error ? error.message : "Failed to resume action" }));
795
+ throw error;
796
+ }
797
+ });
798
+ }
799
+ }
800
+ }
801
+ function createStreamState() {
802
+ return {
803
+ currentContent: "",
804
+ currentMessageId: generateMessageId(),
805
+ activeToolCallCount: 0,
806
+ newMessageIds: new Set(),
807
+ sources: [],
808
+ toolCallToActionId: {},
809
+ };
810
+ }
811
+ function upsertMessage(setState, message, isTyping) {
812
+ setState(prev => {
813
+ const existingIndex = prev.messages.findIndex(m => m.id === message.id);
814
+ if (existingIndex >= 0) {
815
+ const newMessages = [...prev.messages];
816
+ newMessages[existingIndex] = message;
817
+ return { ...prev, messages: newMessages, isTyping, isLoading: false };
818
+ }
819
+ return {
820
+ ...prev,
821
+ messages: [...prev.messages, message],
822
+ isTyping,
823
+ isLoading: false,
824
+ };
825
+ });
826
+ }
827
+ function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionId) {
828
+ setState(prev => ({
829
+ ...prev,
830
+ messages: prev.messages.map(msg => (messageIds.has(msg.id)
831
+ ? { ...msg, sources, toolCallToActionId }
832
+ : msg)),
833
+ isTyping: false,
834
+ }));
835
+ }
836
+ function handleContentEvent(event, streamState, onMessageUpdate, setState) {
837
+ streamState.currentContent += event.content;
838
+ const assistantMessage = {
839
+ id: streamState.currentMessageId,
840
+ message: { role: "assistant", content: streamState.currentContent },
841
+ timestamp: new Date().toISOString(),
842
+ sources: streamState.sources,
843
+ isStreaming: true,
844
+ };
845
+ streamState.newMessageIds.add(assistantMessage.id);
846
+ onMessageUpdate(assistantMessage);
847
+ const hasContent = assistantMessage.message.content?.trim().length || 0 > 0;
848
+ const isToolExecuting = streamState.activeToolCallCount > 0;
849
+ const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
850
+ upsertMessage(setState, assistantMessage, isTyping);
851
+ }
852
+ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
853
+ if (streamState.currentContent.trim()) {
854
+ const finalAssistant = {
855
+ id: streamState.currentMessageId,
856
+ message: { role: "assistant", content: streamState.currentContent },
857
+ timestamp: new Date().toISOString(),
858
+ sources: streamState.sources,
859
+ isStreaming: false,
860
+ };
861
+ streamState.newMessageIds.add(finalAssistant.id);
862
+ onMessageUpdate(finalAssistant);
863
+ upsertMessage(setState, finalAssistant, true);
864
+ streamState.currentContent = "";
865
+ streamState.currentMessageId = generateMessageId();
866
+ }
867
+ const toolMessageId = event.tool_call_id;
868
+ streamState.activeToolCallCount += 1;
869
+ streamState.newMessageIds.add(toolMessageId);
870
+ const toolMessage = {
871
+ id: toolMessageId,
872
+ sources: [],
873
+ message: { role: "tool", content: "", tool_call_id: event.tool_call_id, name: event.tool_name },
874
+ timestamp: new Date().toISOString(),
875
+ isStreaming: true,
876
+ toolExecuting: event.tool_name,
877
+ };
878
+ upsertMessage(setState, toolMessage, true);
879
+ }
880
+ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
881
+ // Update state and mark action as done in a single setState call
882
+ setState(prev => {
883
+ const messages = prev.messages.map((msg) => {
884
+ const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
885
+ if (!matchesToolCall) {
886
+ return msg;
887
+ }
888
+ const existingName = msg.message.name || event.tool_name;
889
+ return {
890
+ ...msg,
891
+ message: {
892
+ role: "tool",
893
+ content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
894
+ tool_call_id: event.tool_call_id,
895
+ name: existingName,
896
+ },
897
+ isStreaming: false,
898
+ toolExecuting: existingName,
899
+ action: msg.action ? {
900
+ ...msg.action,
901
+ state: event.state || msg.action.state,
902
+ done: true, // Mark action as completed
903
+ } : undefined,
904
+ };
905
+ });
906
+ return { ...prev, messages, isTyping: false, isLoading: false };
907
+ });
908
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
909
+ }
910
+ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
911
+ setState(prev => {
912
+ const messages = prev.messages.map((entry) => {
913
+ const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === event.tool_call_id;
914
+ if (!matchesToolCall) {
915
+ return entry;
916
+ }
917
+ const name = entry.message.name || "tool";
918
+ const toolMessage = {
919
+ ...entry,
920
+ message: {
921
+ role: "tool",
922
+ content: event.error || "Tool execution failed",
923
+ tool_call_id: event.tool_call_id,
924
+ name,
925
+ },
926
+ timestamp: new Date().toISOString(),
927
+ isStreaming: false,
928
+ isError: true,
929
+ toolExecuting: name,
930
+ };
931
+ return toolMessage;
932
+ });
933
+ return { ...prev, messages, isTyping: false, isLoading: false };
934
+ });
935
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
936
+ }
937
+ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
938
+ setState(prev => {
939
+ const messages = prev.messages.map((entry) => {
940
+ const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
941
+ if (!matchesToolCall) {
942
+ return entry;
943
+ }
944
+ const existingName = entry.message.name || toolName;
945
+ return {
946
+ ...entry,
947
+ message: {
948
+ role: "tool",
949
+ content: typeof entry.message.content === "string" ? entry.message.content : "",
950
+ tool_call_id: toolCallId,
951
+ name: existingName,
952
+ },
953
+ isStreaming: false,
954
+ toolExecuting: existingName,
955
+ action: entry.action ? {
956
+ ...entry.action,
957
+ done: true, // Mark action as completed
958
+ } : undefined,
959
+ };
960
+ });
961
+ return { ...prev, messages, isTyping: false, isLoading: false };
962
+ });
963
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
964
+ }
965
+ function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
966
+ streamState.sources = event.sources;
967
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
968
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
969
+ }
970
+ function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
971
+ const toolNames = event.tool_calls.map(call => call.name).join(", ");
972
+ const notice = toolNames
973
+ ? `Awaiting external tool results: ${toolNames}.`
974
+ : "Awaiting external tool results.";
975
+ const haltMessage = {
976
+ id: generateMessageId(),
977
+ message: { role: "assistant", content: notice },
978
+ timestamp: new Date().toISOString(),
979
+ sources: [],
980
+ isError: true,
981
+ };
982
+ onMessageUpdate(haltMessage);
983
+ upsertMessage(setState, haltMessage, false);
984
+ setState(prev => ({ ...prev, error: "Awaiting external tool handling." }));
985
+ }
986
+ function handleErrorEvent(event, _streamState, onMessageUpdate, setState) {
987
+ const errorMessage = {
988
+ id: generateMessageId(),
989
+ message: { role: "assistant", content: `⚠️ ${event.error}` },
990
+ timestamp: new Date().toISOString(),
991
+ sources: [],
992
+ isError: true,
993
+ };
994
+ onMessageUpdate(errorMessage);
995
+ upsertMessage(setState, errorMessage, false);
996
+ setState(prev => ({ ...prev, error: event.error }));
997
+ }
998
+ const eventHandlers = {
999
+ content: handleContentEvent,
1000
+ tool_start: handleToolStartEvent,
1001
+ tool_end: handleToolEndEvent,
1002
+ tool_error: handleToolErrorEvent,
1003
+ done: handleDoneEvent,
1004
+ halt: handleHaltEvent,
1005
+ error: handleErrorEvent,
1006
+ action_request: () => { },
1007
+ };
1008
+ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
1009
+ if (event.type === "tool_start" || event.type === "tool_end" || event.type === "tool_error" || event.type === "action_request" || event.type === "done" || event.type === "halt") {
1010
+ console.log("[Widget] stream event:", {
1011
+ type: event.type,
1012
+ toolCallId: "tool_call_id" in event ? event.tool_call_id : undefined,
1013
+ toolName: "tool_name" in event ? event.tool_name : undefined,
1014
+ });
1015
+ }
1016
+ const handler = eventHandlers[event.type];
1017
+ if (handler) {
1018
+ handler(event, streamState, onMessageUpdate, setState);
1019
+ }
1020
+ else {
1021
+ console.warn('[Chat] Unknown event type:', event.type);
1022
+ }
1023
+ }
1024
+ async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
1025
+ let pendingEvent = initialEvent;
1026
+ while (pendingEvent) {
1027
+ streamState.toolCallToActionId = pendingEvent.tool_call_to_action_id;
1028
+ const resumeToolCallId = pendingEvent.tool_call_id;
1029
+ const existingToolMessage = getMessages().find((entry) => entry.message.role === "tool" && entry.message.tool_call_id === resumeToolCallId);
1030
+ const toolMessageId = existingToolMessage?.id ?? resumeToolCallId;
1031
+ const toolName = existingToolMessage?.message.name ?? "tool";
1032
+ const toolMessage = {
1033
+ id: toolMessageId,
1034
+ sources: [],
1035
+ message: {
1036
+ role: "tool",
1037
+ content: "",
1038
+ tool_call_id: resumeToolCallId,
1039
+ name: toolName,
1040
+ },
1041
+ timestamp: new Date().toISOString(),
1042
+ isStreaming: true,
1043
+ toolExecuting: toolName,
1044
+ action: {
1045
+ implementation: pendingEvent.implementation,
1046
+ toolCallId: pendingEvent.tool_call_id,
1047
+ actionId: pendingEvent.action_id,
1048
+ input: pendingEvent.input,
1049
+ state: pendingEvent.state,
1050
+ done: false, // Action not yet completed
1051
+ },
1052
+ };
1053
+ if (streamState.activeToolCallCount === 0) {
1054
+ streamState.activeToolCallCount = 1;
1055
+ }
1056
+ onMessageUpdate(toolMessage);
1057
+ upsertMessage(setState, toolMessage, true);
1058
+ const handler = getFrontendActionHandler(pendingEvent.implementation);
1059
+ if (!handler) {
1060
+ const errorMessage = {
1061
+ id: generateMessageId(),
1062
+ message: {
1063
+ role: "assistant",
1064
+ content: `⚠️ No frontend handler for action '${pendingEvent.implementation}'.`,
1065
+ },
1066
+ timestamp: new Date().toISOString(),
1067
+ sources: [],
1068
+ isError: true,
1069
+ };
1070
+ onMessageUpdate(errorMessage);
1071
+ upsertMessage(setState, errorMessage, false);
1072
+ setState(prev => ({ ...prev, error: `Missing frontend handler: ${pendingEvent?.implementation}` }));
1073
+ return;
1074
+ }
1075
+ let nextState;
1076
+ try {
1077
+ nextState = await handler(pendingEvent.input, pendingEvent.state, {
1078
+ widgetId,
1079
+ conversationId,
1080
+ toolCallId: pendingEvent.tool_call_id,
1081
+ actionId: pendingEvent.action_id,
1082
+ implementation: pendingEvent.implementation,
1083
+ });
1084
+ }
1085
+ catch (error) {
1086
+ const errorMessage = error instanceof Error ? error.message : "Frontend action failed.";
1087
+ const errorMessageEntry = {
1088
+ id: generateMessageId(),
1089
+ message: { role: "assistant", content: `⚠️ ${errorMessage}` },
1090
+ timestamp: new Date().toISOString(),
1091
+ sources: [],
1092
+ isError: true,
1093
+ };
1094
+ onMessageUpdate(errorMessageEntry);
1095
+ upsertMessage(setState, errorMessageEntry, false);
1096
+ setState(prev => ({ ...prev, error: errorMessage }));
1097
+ return;
1098
+ }
1099
+ pendingEvent = null;
1100
+ const updatedToolMessage = {
1101
+ ...toolMessage,
1102
+ action: toolMessage.action
1103
+ ? {
1104
+ ...toolMessage.action,
1105
+ state: nextState,
1106
+ }
1107
+ : undefined,
1108
+ };
1109
+ upsertMessage(setState, updatedToolMessage, true);
1110
+ let streamEnded = false;
1111
+ for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
1112
+ if (event.type === "action_request") {
1113
+ pendingEvent = event;
1114
+ break;
1115
+ }
1116
+ if (event.type === "done") {
1117
+ // Don't extract and update state from done event - the state was already
1118
+ // updated by tool_end event or by the user's frontend action.
1119
+ finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
1120
+ // Handle the done event but skip the tool finalization part since we already did it
1121
+ streamState.sources = event.sources;
1122
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
1123
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
1124
+ streamEnded = true;
1125
+ continue; // Skip handleStreamEvent for done events to avoid state conflicts
1126
+ }
1127
+ if (event.type === "error") {
1128
+ const errorMessage = {
1129
+ id: generateMessageId(),
1130
+ message: {
1131
+ role: "assistant",
1132
+ content: `Error occurred during action execution: ${event.error}`,
1133
+ },
1134
+ timestamp: new Date().toISOString(),
1135
+ sources: [],
1136
+ isError: true,
1137
+ };
1138
+ upsertMessage(setState, errorMessage, false);
1139
+ return;
1140
+ }
1141
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
1142
+ }
1143
+ // If stream ended without a done event (e.g., only tool_end was sent), finalize the tool message
1144
+ if (!streamEnded && !pendingEvent) {
1145
+ finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
1146
+ }
1147
+ }
1148
+ }
597
1149
  function deriveErrorInfo(error) {
598
1150
  if (error instanceof ApiError) {
599
1151
  const retryAfterSeconds = typeof error.retryAfterMs === 'number'
@@ -666,6 +1218,10 @@ function useChat(options) {
666
1218
  conversationId: '', // Will be set after loading conversation
667
1219
  config: null,
668
1220
  });
1221
+ const stateRef = react.useRef(state);
1222
+ react.useEffect(() => {
1223
+ stateRef.current = state;
1224
+ }, [state]);
669
1225
  // Chat history state
670
1226
  const [conversations, setConversations] = react.useState([]);
671
1227
  const apiClient = react.useRef(new WidgetApiClient({ widgetId, apiUrl }));
@@ -673,18 +1229,12 @@ function useChat(options) {
673
1229
  react.useEffect(() => {
674
1230
  // Skip initialization in preview mode
675
1231
  if (skipInitialization) {
676
- console.log('[useChat] Skipping initialization (preview mode)');
677
1232
  return;
678
1233
  }
679
1234
  let isMounted = true;
680
- console.log('[useChat] Effect running, mounting component');
681
1235
  const initialize = async () => {
682
1236
  try {
683
- console.log('[useChat] Fetching config...');
684
1237
  const config = await apiClient.current.getConfig();
685
- console.log('[useChat] Config fetched successfully:', {
686
- hasAppearance: !!config.appearance,
687
- });
688
1238
  const persistConversation = config.settings.persistConversation ?? true;
689
1239
  let conversationId = '';
690
1240
  let messages = [];
@@ -695,7 +1245,7 @@ function useChat(options) {
695
1245
  try {
696
1246
  const conversation = await apiClient.current.getOrCreateConversation(storedId);
697
1247
  conversationId = conversation.id;
698
- messages = conversation.messages;
1248
+ messages = hydrateMessages(conversation.messages);
699
1249
  }
700
1250
  catch (conversationError) {
701
1251
  console.warn('Failed to load existing conversation:', conversationError);
@@ -703,16 +1253,19 @@ function useChat(options) {
703
1253
  }
704
1254
  }
705
1255
  if (!isMounted) {
706
- console.log('[useChat] Component unmounted, skipping state update');
707
1256
  return;
708
1257
  }
709
- console.log('[useChat] Setting config in state');
1258
+ const hydratedMessages = hydrateMessages(messages);
710
1259
  setState(prev => ({
711
1260
  ...prev,
712
1261
  config,
713
1262
  conversationId,
714
- messages,
1263
+ messages: hydratedMessages,
715
1264
  }));
1265
+ // Setup resume callbacks for incomplete actions
1266
+ if (conversationId) {
1267
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
1268
+ }
716
1269
  }
717
1270
  catch (error) {
718
1271
  console.error('[useChat] Error fetching config:', error);
@@ -727,8 +1280,13 @@ function useChat(options) {
727
1280
  };
728
1281
  initialize();
729
1282
  return () => {
730
- console.log('[useChat] Effect cleanup, unmounting component');
731
1283
  isMounted = false;
1284
+ // Cleanup resume callbacks
1285
+ state.messages.forEach(message => {
1286
+ if (message.action?.toolCallId) {
1287
+ unregisterActionResumeCallback(message.action.toolCallId);
1288
+ }
1289
+ });
732
1290
  };
733
1291
  }, [widgetId, apiUrl, onError]);
734
1292
  // Save conversation when messages change
@@ -741,9 +1299,6 @@ function useChat(options) {
741
1299
  saveConversation(widgetId, state.conversationId, state.messages);
742
1300
  }
743
1301
  }, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
744
- /**
745
- * Send a message
746
- */
747
1302
  const sendMessage = react.useCallback(async (content, files) => {
748
1303
  const trimmedContent = content.trim();
749
1304
  const hasFiles = !!files && files.length > 0;
@@ -752,7 +1307,7 @@ function useChat(options) {
752
1307
  const userMessage = {
753
1308
  id: generateMessageId(),
754
1309
  message: {
755
- type: 'human',
1310
+ role: "user",
756
1311
  content: trimmedContent,
757
1312
  },
758
1313
  timestamp: new Date().toISOString(),
@@ -773,7 +1328,7 @@ function useChat(options) {
773
1328
  const conversation = await apiClient.current.getOrCreateConversation();
774
1329
  conversationId = conversation.id;
775
1330
  setState(prev => {
776
- const serverMessages = conversation.messages ?? [];
1331
+ const serverMessages = hydrateMessages(conversation.messages ?? []);
777
1332
  if (serverMessages.length === 0) {
778
1333
  return {
779
1334
  ...prev,
@@ -807,48 +1362,20 @@ function useChat(options) {
807
1362
  }
808
1363
  }
809
1364
  }
810
- // Determine if widget has actions (use agent endpoint)
811
- const useAgent = state.config?.behavior.agentic || (state.config?.actions && state.config.actions.length > 0);
812
1365
  // Stream the response
813
1366
  let lastStreamedMessage = null;
814
- const stream = useAgent
815
- ? apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds)
816
- : apiClient.current.sendMessageStream(conversationId, trimmedContent, fileIds);
817
- for await (const message of stream) {
818
- lastStreamedMessage = message;
819
- // Update state with streamed message
820
- setState(prev => {
821
- const existingIndex = prev.messages.findIndex(m => m.id === message.id);
822
- if (existingIndex >= 0) {
823
- // Update existing streaming message
824
- const newMessages = [...prev.messages];
825
- newMessages[existingIndex] = message;
826
- // Show typing indicator if:
827
- // 1. Message is streaming AND has no content (waiting for first token or after tool call)
828
- // 2. Message is a tool execution (shows loading spinner on the tool)
829
- const isAIMessage = message.message.type === 'ai';
830
- const hasContent = isAIMessage && message.message.content.trim().length > 0;
831
- const isToolExecuting = message.toolExecuting !== undefined;
832
- return {
833
- ...prev,
834
- messages: newMessages,
835
- isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
836
- isLoading: false,
837
- };
838
- }
839
- else {
840
- // Add new streaming message
841
- const isAIMessage = message.message.type === 'ai';
842
- const hasContent = isAIMessage && message.message.content.trim().length > 0;
843
- const isToolExecuting = message.toolExecuting !== undefined;
844
- return {
845
- ...prev,
846
- messages: [...prev.messages, message],
847
- isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
848
- isLoading: false,
849
- };
850
- }
851
- });
1367
+ const streamState = createStreamState();
1368
+ const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds);
1369
+ for await (const event of stream) {
1370
+ if (event.type === "action_request") {
1371
+ await handleActionLoop(apiClient.current, event, streamState, (message) => {
1372
+ lastStreamedMessage = message;
1373
+ }, setState, widgetId, conversationId, () => stateRef.current.messages);
1374
+ break;
1375
+ }
1376
+ handleStreamEvent(event, streamState, (message) => {
1377
+ lastStreamedMessage = message;
1378
+ }, setState);
852
1379
  }
853
1380
  // Stream completed - finalize state
854
1381
  setState(prev => ({
@@ -869,7 +1396,7 @@ function useChat(options) {
869
1396
  const fallbackAssistantMessage = {
870
1397
  id: generateMessageId(),
871
1398
  message: {
872
- type: 'ai',
1399
+ role: "assistant",
873
1400
  content: fallbackMessage,
874
1401
  },
875
1402
  timestamp: new Date().toISOString(),
@@ -888,7 +1415,7 @@ function useChat(options) {
888
1415
  const errorAssistantMessage = {
889
1416
  id: generateMessageId(),
890
1417
  message: {
891
- type: 'ai',
1418
+ role: "assistant",
892
1419
  content: `⚠️ ${errorInfo.message}`,
893
1420
  },
894
1421
  timestamp: new Date().toISOString(),
@@ -926,8 +1453,13 @@ function useChat(options) {
926
1453
  */
927
1454
  const submitFeedback = react.useCallback(async (messageId, feedback) => {
928
1455
  try {
1456
+ const message = state.messages.find(msg => msg.id === messageId);
1457
+ const messageContent = typeof message?.message.content === "string" ? message.message.content : undefined;
1458
+ const meta = message
1459
+ ? { role: message.message.role, content: messageContent, timestamp: message.timestamp }
1460
+ : undefined;
929
1461
  console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
930
- await apiClient.current.submitFeedback(state.conversationId, messageId, feedback);
1462
+ await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
931
1463
  // Update message with feedback
932
1464
  setState(prev => ({
933
1465
  ...prev,
@@ -961,9 +1493,6 @@ function useChat(options) {
961
1493
  startedAt: entry.lastUpdated,
962
1494
  })));
963
1495
  }, [widgetId, state.config?.settings.persistConversation]);
964
- /**
965
- * Switch to a different conversation (from localStorage first, then fetch from server if needed)
966
- */
967
1496
  const switchConversation = react.useCallback(async (conversationId) => {
968
1497
  const persistConversation = state.config?.settings.persistConversation ?? true;
969
1498
  // First try to load from localStorage
@@ -973,25 +1502,33 @@ function useChat(options) {
973
1502
  setState(prev => ({
974
1503
  ...prev,
975
1504
  conversationId: stored.conversationId,
976
- messages: stored.messages,
1505
+ messages: hydrateMessages(stored.messages),
977
1506
  }));
978
1507
  setActiveConversation(widgetId, conversationId);
979
1508
  return;
980
1509
  }
981
1510
  }
982
- // If not in localStorage, fetch from server
983
1511
  setState(prev => ({ ...prev, isLoading: true, error: null }));
984
1512
  try {
985
1513
  const conversation = await apiClient.current.getOrCreateConversation(conversationId);
1514
+ const hydratedMessages = hydrateMessages(conversation.messages);
1515
+ // Clear old resume callbacks
1516
+ state.messages.forEach(message => {
1517
+ if (message.action?.toolCallId) {
1518
+ unregisterActionResumeCallback(message.action.toolCallId);
1519
+ }
1520
+ });
986
1521
  setState(prev => ({
987
1522
  ...prev,
988
1523
  conversationId: conversation.id,
989
- messages: conversation.messages,
1524
+ messages: hydratedMessages,
990
1525
  isLoading: false,
991
1526
  }));
1527
+ // Setup new resume callbacks
1528
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
992
1529
  // Save to local storage
993
1530
  if (persistConversation && isStorageAvailable()) {
994
- saveConversation(widgetId, conversation.id, conversation.messages);
1531
+ saveConversation(widgetId, conversation.id, hydratedMessages);
995
1532
  }
996
1533
  }
997
1534
  catch (error) {
@@ -999,9 +1536,6 @@ function useChat(options) {
999
1536
  setState(prev => ({ ...prev, isLoading: false, error: errorInfo.message }));
1000
1537
  }
1001
1538
  }, [widgetId, state.config?.settings.persistConversation]);
1002
- /**
1003
- * Start a new conversation (keeps history)
1004
- */
1005
1539
  const startNewConversation = react.useCallback(() => {
1006
1540
  setState(prev => ({
1007
1541
  ...prev,
@@ -1009,15 +1543,11 @@ function useChat(options) {
1009
1543
  conversationId: '',
1010
1544
  error: null,
1011
1545
  }));
1012
- // Clear active conversation but keep history
1013
1546
  const persistConversation = state.config?.settings.persistConversation ?? true;
1014
1547
  if (persistConversation && isStorageAvailable()) {
1015
1548
  clearConversation(widgetId);
1016
1549
  }
1017
1550
  }, [widgetId, state.config?.settings.persistConversation]);
1018
- /**
1019
- * Delete a conversation from history
1020
- */
1021
1551
  const deleteConversation$1 = react.useCallback((conversationId) => {
1022
1552
  const persistConversation = state.config?.settings.persistConversation ?? true;
1023
1553
  if (!persistConversation || !isStorageAvailable()) {
@@ -27871,12 +28401,12 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27871
28401
  hour12: true,
27872
28402
  });
27873
28403
  };
27874
- const msgType = message.message.type;
28404
+ const role = message.message.role;
27875
28405
  const isError = message.isError || false;
27876
- const isTool = msgType === 'tool';
27877
- const isAssistant = msgType === 'ai';
27878
- const isSystem = msgType === 'system';
27879
- const isHuman = msgType === 'human';
28406
+ const isTool = role === "tool";
28407
+ const isAssistant = role === "assistant";
28408
+ const isSystem = role === "system";
28409
+ const isHuman = role === "user";
27880
28410
  // Tool messages are now handled by ToolMessageGroup in MessageList
27881
28411
  if (isTool) {
27882
28412
  return null;
@@ -27887,7 +28417,10 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27887
28417
  const hasContent = aiContent.trim().length > 0;
27888
28418
  if (!hasContent)
27889
28419
  return null;
27890
- 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 })] }), 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 }))] }));
28420
+ const actionRenderer = message.action
28421
+ ? getActionRenderer(message.action.implementation)
28422
+ : undefined;
28423
+ 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 }))] }));
27891
28424
  }
27892
28425
  // System message rendering
27893
28426
  if (isSystem) {
@@ -27895,7 +28428,7 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27895
28428
  }
27896
28429
  // Human message rendering
27897
28430
  if (isHuman) {
27898
- const userContent = message.message.content.split('--- File Content ---')[0];
28431
+ const userContent = (message.message.content || '').split('--- File Content ---')[0];
27899
28432
  return (jsxRuntime.jsxs("div", { className: "ai-chat-message user", children: [jsxRuntime.jsx("div", { className: "ai-chat-message-content", children: userContent }), showTimestamp && (jsxRuntime.jsx("div", { className: "ai-chat-message-meta", children: jsxRuntime.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }) }))] }));
27900
28433
  }
27901
28434
  return null;
@@ -27912,13 +28445,31 @@ const GearIcon = ({ spinning = false }) => (jsxRuntime.jsxs("svg", { className:
27912
28445
  const CheckIcon = () => (jsxRuntime.jsx("svg", { className: "ai-chat-tool-check", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27913
28446
  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" }) }));
27914
28447
  const ToolMessageGroup = ({ messages }) => {
27915
- const isAnyLoading = messages.some(m => m.isStreaming);
27916
- return (jsxRuntime.jsx("div", { className: "ai-chat-message tool", children: jsxRuntime.jsxs("div", { className: "ai-chat-tool-row", children: [jsxRuntime.jsx(GearIcon, { spinning: isAnyLoading }), jsxRuntime.jsx("div", { className: "ai-chat-tool-badges", children: messages.map((message) => {
27917
- const toolName = message.toolExecuting || message.message.name || 'Tool';
27918
- const hasError = message.isError || false;
27919
- const isLoading = message.isStreaming;
27920
- return (jsxRuntime.jsxs("div", { className: `ai-chat-tool-badge ${isLoading ? 'loading' : hasError ? 'error' : 'completed'}`, children: [!isLoading && (hasError ? jsxRuntime.jsx(ErrorIcon, {}) : jsxRuntime.jsx(CheckIcon, {})), jsxRuntime.jsx("span", { className: "tool-name", children: formatToolName(toolName) })] }, message.id));
27921
- }) })] }) }));
28448
+ // Check if any message is loading (for actions, check done flag; otherwise check isStreaming)
28449
+ const isAnyLoading = messages.some(m => {
28450
+ if (m.action) {
28451
+ return !(m.action.done ?? false);
28452
+ }
28453
+ return m.isStreaming;
28454
+ });
28455
+ const actionMessages = messages.filter(message => message.action);
28456
+ return (jsxRuntime.jsxs("div", { className: "ai-chat-message tool", children: [jsxRuntime.jsxs("div", { className: "ai-chat-tool-row", children: [jsxRuntime.jsx(GearIcon, { spinning: isAnyLoading }), jsxRuntime.jsx("div", { className: "ai-chat-tool-badges", children: messages.map((message) => {
28457
+ const toolName = message.toolExecuting || message.message.name || 'Tool';
28458
+ const hasError = message.isError || false;
28459
+ // For actions, check if done flag is set; otherwise fall back to isStreaming
28460
+ const isDone = message.action ? (message.action.done ?? false) : !message.isStreaming;
28461
+ const isLoading = !isDone;
28462
+ return (jsxRuntime.jsxs("div", { className: `ai-chat-tool-badge ${isLoading ? 'loading' : hasError ? 'error' : 'completed'}`, children: [!isLoading && (hasError ? jsxRuntime.jsx(ErrorIcon, {}) : jsxRuntime.jsx(CheckIcon, {})), jsxRuntime.jsx("span", { className: "tool-name", children: formatToolName(toolName) })] }, message.id));
28463
+ }) })] }), actionMessages.map((message) => {
28464
+ if (!message.action) {
28465
+ return null;
28466
+ }
28467
+ const renderer = getActionRenderer(message.action.implementation);
28468
+ if (!renderer) {
28469
+ return null;
28470
+ }
28471
+ return (jsxRuntime.jsx("div", { className: "ai-chat-tool-action", children: renderer(message) }, `action-${message.id}`));
28472
+ })] }));
27922
28473
  };
27923
28474
 
27924
28475
  const TypingIndicator = () => {
@@ -27943,6 +28494,14 @@ const SuggestedQuestions = ({ questions, onQuestionClick, }) => {
27943
28494
  const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', welcomeTitle, welcomeMessage, suggestedQuestions, onSuggestedQuestionClick, onFeedback, }) => {
27944
28495
  const containerRef = react.useRef(null);
27945
28496
  const messagesEndRef = react.useRef(null);
28497
+ // Check if there's an active action awaiting user input
28498
+ const hasActiveAction = react.useMemo(() => {
28499
+ return messages.some(msg => msg.action &&
28500
+ msg.action.state &&
28501
+ msg.action.state.status !== 'completed' &&
28502
+ msg.action.state.status !== 'booked' &&
28503
+ msg.action.state.status !== 'failed');
28504
+ }, [messages]);
27946
28505
  // Auto-scroll to bottom only on initial mount/load
27947
28506
  react.useEffect(() => {
27948
28507
  const container = containerRef.current;
@@ -27971,16 +28530,16 @@ const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, s
27971
28530
  }
27972
28531
  };
27973
28532
  for (const message of messages) {
27974
- if (message.message.type === 'tool') {
28533
+ if (message.message.role === "tool") {
27975
28534
  // Add to current tool group
27976
28535
  currentToolGroup.push(message);
27977
28536
  }
27978
- else if (message.message.type === 'human') {
28537
+ else if (message.message.role === "user") {
27979
28538
  // Human message breaks tool grouping
27980
28539
  flushToolGroup();
27981
28540
  result.push({ type: 'message', message });
27982
28541
  }
27983
- else if (message.message.type === 'ai') {
28542
+ else if (message.message.role === "assistant") {
27984
28543
  // Skip empty AI messages
27985
28544
  const content = (message.message.content || '').trim();
27986
28545
  if (!content) {
@@ -28006,7 +28565,7 @@ const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, s
28006
28565
  return (jsxRuntime.jsx(ToolMessageGroup, { messages: item.messages }, `tool-group-${index}`));
28007
28566
  }
28008
28567
  return (jsxRuntime.jsx(Message, { message: item.message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, showSources: showSources, sourceDisplayMode: sourceDisplayMode, onFeedback: onFeedback }, item.message.id));
28009
- }), isTyping && showTypingIndicator && jsxRuntime.jsx(TypingIndicator, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }));
28568
+ }), isTyping && showTypingIndicator && !hasActiveAction && jsxRuntime.jsx(TypingIndicator, {}), jsxRuntime.jsx("div", { ref: messagesEndRef })] }));
28010
28569
  };
28011
28570
 
28012
28571
  // Allowed file types
@@ -28096,7 +28655,6 @@ const ChatWindow = ({ messages, isLoading, isTyping, error, config, onSendMessag
28096
28655
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
28097
28656
  // Override props for live preview
28098
28657
  headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
28099
- console.log('[ChatWindow] Rendering ChatWindow component');
28100
28658
  const appearance = config?.appearance;
28101
28659
  const settings = config?.settings;
28102
28660
  // Check if chat history should be shown (requires both persistConversation AND showChatHistory)
@@ -28107,13 +28665,6 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
28107
28665
  const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
28108
28666
  const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
28109
28667
  const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
28110
- console.log('[ChatWindow] Appearance values:', {
28111
- size,
28112
- headerTitle,
28113
- welcomeTitle,
28114
- welcomeMessage,
28115
- inputPlaceholder,
28116
- });
28117
28668
  // Track if history panel is open
28118
28669
  const [showHistory, setShowHistory] = react.useState(false);
28119
28670
  // History exit animation when starting a new chat from overview
@@ -28158,7 +28709,7 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
28158
28709
  };
28159
28710
  // Check if message limit is reached
28160
28711
  const maxMessages = settings?.maxMessagesPerSession;
28161
- const userMessageCount = messages.filter(m => m.message.type === 'human').length;
28712
+ const userMessageCount = messages.filter(m => m.message.role === "user").length;
28162
28713
  const isLimitReached = maxMessages ? userMessageCount >= maxMessages : false;
28163
28714
  const handleQuestionClick = (question) => {
28164
28715
  onSendMessage(question);
@@ -28568,34 +29119,7 @@ function createThemeObserver(element, callback) {
28568
29119
  return observer;
28569
29120
  }
28570
29121
 
28571
- function styleInject(css, ref) {
28572
- if ( ref === void 0 ) ref = {};
28573
- var insertAt = ref.insertAt;
28574
-
28575
- if (typeof document === 'undefined') { return; }
28576
-
28577
- var head = document.head || document.getElementsByTagName('head')[0];
28578
- var style = document.createElement('style');
28579
- style.type = 'text/css';
28580
-
28581
- if (insertAt === 'top') {
28582
- if (head.firstChild) {
28583
- head.insertBefore(style, head.firstChild);
28584
- } else {
28585
- head.appendChild(style);
28586
- }
28587
- } else {
28588
- head.appendChild(style);
28589
- }
28590
-
28591
- if (style.styleSheet) {
28592
- style.styleSheet.cssText = css;
28593
- } else {
28594
- style.appendChild(document.createTextNode(css));
28595
- }
28596
- }
28597
-
28598
- var css_248z = ".ai-chat-widget{--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:18px;--radius-pill:9999px;--radius-window-top:22px;--radius-window-bottom:44px;--radius-window-gutter:16px;--radius-chat-bubble:14px;--radius-preset-badge:13px;--radius-history-item:14px;--radius-action-badge: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{--bg-primary:#282625;--bg-secondary:#4a4846;--bg-tertiary:#484848;--bg-hover:#484848;--text-primary:#fff;--text-secondary:#fff;--text-muted:#a1a1aa;--text-placeholder:#71717a;--border-default:#5d5b5b;--border-subtle:#5d5b5b;--border-muted:#5d5b5b;--user-bg:#484848;--user-text:#fff;--user-bg-hover:#5a5a5a;--agent-bg:transparent;--agent-text:#fff;--input-bg:#4a4846;--input-border:#5d5b5b;--input-text:#fff;--btn-primary-bg:#fff;--btn-primary-text:#312f2d;--btn-secondary-bg:transparent;--btn-secondary-text:#a1a1aa;--shadow-window:0px 0px 15px 9px rgba(0,0,0,.2);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03);--shadow-input:0px 0px 10px rgba(0,0,0,.15)}.ai-chat-widget{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget-container{font-size:var(--text-sm);line-height:1.5;position:fixed;z-index:var(--widget-z-index,9999)}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}@keyframes windowOpen{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes windowClose{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes messageSlideIn{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes welcomeFadeIn{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes typingPulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-4px) scale(1.1)}}@keyframes ai-chat-tool-active{0%,to{background:var(--bg-secondary);opacity:1}50%{background:var(--bg-tertiary);opacity:1}}@keyframes feedbackMorph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes checkmarkPop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes ai-chat-history-exit{to{opacity:0;transform:translateY(-18px)}}@media (max-width:480px){.ai-chat-window{animation:mobileSlideUp var(--duration-normal) var(--spring-smooth);border-radius:0!important;bottom:0!important;height:100%!important;left:0!important;position:fixed!important;right:0!important;top:0!important;width:100%!important}@keyframes mobileSlideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}.ai-chat-header{padding-top:max(16px,env(safe-area-inset-top))}.ai-chat-input-container{padding-bottom:max(20px,env(safe-area-inset-bottom))}}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--button-border-color,var(--button-color,var(--btn-primary-bg)));border-radius:50%;box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));cursor:pointer;display:flex;height:var(--button-size,56px);justify-content:center;overflow:hidden;position:relative;transition:filter var(--duration-fast) ease,transform var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{transform:scale(1.02)}.ai-chat-button:active{transform:scale(.98)}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-window{animation:windowOpen var(--duration-slow,.35s) var(--spring-bounce,cubic-bezier(.34,1.56,.64,1));background:var(--bg-primary,#fff);border:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px);box-shadow:var(--shadow-window,0 0 15px 5px rgba(0,0,0,.08));display:flex;flex-direction:column;overflow:hidden;position:absolute;transform-origin:bottom right;z-index:2}.ai-chat-widget.dark .ai-chat-window{background:var(--bg-primary,#282625);border-color:var(--border-default,#5d5b5b);border-width:.7px}.ai-chat-window.closing{animation:windowClose var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:var(--window-height,580px);width:var(--window-width,380px)}.ai-chat-window.size-medium{height:var(--window-height,720px);width:var(--window-width,440px)}.ai-chat-window.size-large{height:var(--window-height,820px);width:var(--window-width,520px)}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-header{align-items:center;background:var(--bg-primary,#fff);border-bottom:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) 0 0;display:flex;justify-content:space-between;padding:18px var(--space-md,16px);position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:var(--bg-primary,#282625);border-bottom-color:var(--border-default,#5d5b5b);border-bottom-width:.7px}.ai-chat-header.is-history{padding-left:var(--space-md)}.ai-chat-header.is-history .ai-chat-title{flex:1;min-width:0;overflow:hidden;padding-right:var(--space-lg);text-overflow:ellipsis;white-space:nowrap}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:var(--space-lg)}.ai-chat-header-actions{align-items:center;display:flex;gap:var(--space-sm)}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-xl,22px);font-weight:var(--font-weight-bold,700);letter-spacing:-.02em}.ai-chat-widget.dark .ai-chat-title{color:var(--text-primary,#fff)}.ai-chat-close-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-primary);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover{color:var(--text-muted)}.ai-chat-close-button:active{transform:scale(.95)}.ai-chat-header-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all var(--duration-fast) ease;width:32px}.ai-chat-header-button:hover{background:var(--bg-secondary);color:var(--text-secondary)}.ai-chat-header-button svg{height:18px;width:18px}.ai-chat-messages{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;align-items:stretch;background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;gap:var(--space-md,16px);justify-content:flex-start;overflow-x:hidden;overflow-y:auto;padding:var(--space-lg,24px) var(--space-md,16px) 100px;position:relative;scroll-behavior:smooth;scrollbar-width:none}.ai-chat-widget.dark .ai-chat-messages{background:var(--bg-primary,#18181b)}.ai-chat-messages::-webkit-scrollbar{display:none}.ai-chat-message{animation:messageSlideIn var(--duration-normal) var(--spring-bounce);display:flex;flex-direction:column;gap:6px}.ai-chat-message-content{word-wrap:break-word;font-size:var(--text-md);line-height:var(--line-height-relaxed);max-width:85%}.ai-chat-message.user{align-items:flex-end}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border:none;border-radius:var(--radius-chat-bubble,15px);box-shadow:none;color:var(--user-text,#000);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#484848);color:var(--user-text,#fff)}.ai-chat-message.user .ai-chat-message-meta{justify-content:flex-end;padding-right:var(--space-xs)}.ai-chat-message.assistant{align-items:flex-start}.ai-chat-message.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);border:none;color:var(--agent-text,#18181b);padding:0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fafafa)}.ai-chat-message.system{align-items:center}.ai-chat-message.system .ai-chat-message-content{background:hsla(48,96%,89%,.8);border-radius:var(--radius-md);color:#92400e;font-size:var(--text-xs);font-style:italic;max-width:90%;padding:var(--space-sm) var(--space-md);text-align:center}.ai-chat-widget.dark .ai-chat-message.system .ai-chat-message-content{background:rgba(120,53,15,.5);color:#fef3c7}.ai-chat-message.tool{align-items:flex-start}.ai-chat-message.tool .ai-chat-message-content{background:rgba(219,234,254,.8);border-radius:var(--radius-chat-bubble);border-bottom-left-radius:var(--radius-xs);color:#1e40af;font-family:Courier New,monospace;font-size:var(--text-sm);padding:var(--space-sm) var(--space-md)}.ai-chat-widget.dark .ai-chat-message.tool .ai-chat-message-content{background:rgba(30,58,138,.5);color:#dbeafe}.ai-chat-message-meta{align-items:center;color:var(--text-muted);display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding-left:var(--space-xs)}.ai-chat-message-timestamp{font-size:var(--text-xs);line-height:1}.ai-chat-typing{align-items:center;animation:messageSlideIn var(--duration-normal) var(--spring-bounce);background:transparent;display:flex;gap:5px;padding:0}.ai-chat-typing-dot{animation:typingPulse 1.4s ease-in-out infinite;background:var(--text-muted);border-radius:50%;height:6px;width:6px}.ai-chat-typing-dot:nth-child(2){animation-delay:.15s}.ai-chat-typing-dot:nth-child(3){animation-delay:.3s}.ai-chat-welcome{align-items:stretch;animation:welcomeFadeIn var(--duration-slow) var(--spring-smooth);display:flex;flex-direction:column;justify-content:flex-start;padding:0;text-align:left}.ai-chat-welcome-text,.ai-chat-welcome-title{align-self:flex-start}.ai-chat-welcome-title{color:var(--text-primary);font-size:var(--text-2xl);font-weight:var(--font-weight-semibold);letter-spacing:-.02em;margin-bottom:var(--space-md)}.ai-chat-welcome-text{color:var(--text-secondary);font-size:var(--text-md);line-height:var(--line-height-relaxed);max-width:100%}.ai-chat-error{align-items:flex-start;align-self:center;background:var(--bg-secondary);border:none;border-radius:var(--radius-chat-bubble);color:var(--text-primary);display:flex;font-size:var(--text-md);font-weight:var(--font-weight-normal);gap:10px;line-height:1.5;margin:0 auto;max-width:90%;padding:10px var(--space-md)}.ai-chat-error:before{align-items:center;background:rgba(239,68,68,.15);border-radius:50%;color:#ef4444;content:\"⚠\";display:flex;flex-shrink:0;font-size:var(--text-xs);font-weight:700;height:18px;justify-content:center;margin-top:2px;width:18px}.ai-chat-widget.dark .ai-chat-error:before{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 12px}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content ol,.ai-chat-message.assistant .ai-chat-message-content ul{margin:8px 0 12px;padding-left:24px}.ai-chat-message.assistant .ai-chat-message-content li{line-height:1.5;margin:6px 0}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content em{font-style:italic}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.06);border-radius:var(--radius-sm);font-family:SF Mono,Consolas,Monaco,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.06);border-radius:var(--radius-md);margin:8px 0 12px;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.08)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;border-radius:0;padding:0}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--btn-primary-bg);color:var(--text-muted);margin:8px 0 12px;padding:4px 0 4px 12px}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content a:hover{opacity:.8}.ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-message.assistant .ai-chat-message-content h2,.ai-chat-message.assistant .ai-chat-message-content h3,.ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-message.assistant .ai-chat-message-content h6{font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);margin:16px 0 8px}.ai-chat-message.assistant .ai-chat-message-content h1:first-child,.ai-chat-message.assistant .ai-chat-message-content h2:first-child,.ai-chat-message.assistant .ai-chat-message-content h3:first-child{margin-top:0}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle);margin:12px 0}.ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#fff) 50%,var(--bg-primary,#fff) 100%);bottom:0;left:0;padding-top:30px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#282625) 50%,var(--bg-primary,#282625) 100%)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px);padding-top:30px}.ai-chat-input-wrapper{align-items:flex-start;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);display:flex;gap:0;height:52px;padding:6px 6px 6px 12px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-widget.dark .ai-chat-input-wrapper{background:var(--input-bg,#4a4846);border-color:var(--input-border,#5d5b5b);border-width:.7px;box-shadow:var(--shadow-input,0 0 10px rgba(0,0,0,.15))}.ai-chat-input-wrapper:focus-within{border-color:var(--text-muted,#a1a1aa)}.ai-chat-input{word-wrap:break-word;background:transparent;border:none;box-sizing:border-box;color:var(--input-text,#000);flex:1;font-family:inherit;font-size:var(--text-md,15px);height:40px;line-height:20px;max-height:40px;min-height:40px;min-width:0;outline:none;overflow-wrap:anywhere;overflow-x:hidden;overflow-y:auto;padding:10px var(--space-sm,8px);resize:none;white-space:pre-wrap;width:0;word-break:break-word}.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;padding:0;transition:all var(--duration-fast,.15s) ease;width:40px}.ai-chat-widget.dark .ai-chat-send-button{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4))}.ai-chat-widget.dark .ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button:hover:not(:disabled){opacity:.8}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.3}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-sm)}.ai-chat-file-item{align-items:center;background:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding:6px 10px}.ai-chat-file-extension{background:var(--btn-primary-bg);border-radius:3px;color:var(--btn-primary-text);display:inline-block;font-size:10px;font-weight:var(--font-weight-semibold);min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:var(--font-weight-medium);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:var(--space-xs);transition:opacity var(--duration-fast) ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-suggested-questions{align-self:flex-end;margin:0;padding:16px 0 0;width:100%}.ai-chat-suggested-questions-list{align-items:center;display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.ai-chat-suggested-question{background:var(--primary-color,var(--button-color,var(--user-bg,#f4f3f0)));border:none;border-radius:var(--radius-preset-badge,13px);color:var(--button-icon-color,var(--user-text,#000));cursor:pointer;font-size:14px;font-weight:400;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,opacity .15s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:var(--primary-color,var(--button-color,var(--user-bg,#484848)));color:var(--button-icon-color,var(--user-text,#fff))}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{filter:brightness(.9)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{filter:brightness(1.15)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question-icon{display:none}.ai-chat-feedback-buttons{align-items:center;display:flex;gap:var(--space-xs)}.ai-chat-feedback{align-items:center;display:inline-flex;gap:0;height:20px}.ai-chat-feedback-button{align-items:center;background:transparent!important;border:none;border-radius:var(--radius-sm);color:var(--text-placeholder);cursor:pointer;display:flex;font-size:var(--text-sm);height:20px;justify-content:center;padding:var(--space-xs);transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:var(--text-secondary)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--text-primary)}.ai-chat-feedback-submitted{align-items:center;animation:feedbackMorph .3s var(--spring-bounce);display:flex;gap:6px}.ai-chat-feedback-checkmark{animation:checkmarkPop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-sm);font-weight:var(--font-weight-medium)}.ai-chat-history-panel{background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-history-panel{background:var(--bg-primary,#18181b)}.ai-chat-history-empty,.ai-chat-history-loading{align-items:center;color:var(--text-muted);display:flex;flex:1;font-size:var(--text-sm);justify-content:center;padding:var(--space-lg);text-align:center}.ai-chat-history-list{-ms-overflow-style:none;display:flex;flex:1;flex-direction:column;gap:var(--space-sm);overflow-y:auto;padding:var(--space-md) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items:center;background:var(--user-bg,#f4f4f5);border-radius:var(--radius-history-item,15px);display:flex;flex-direction:row;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:36px;min-width:0;padding:0 3px 0 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;color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:32px;justify-content:center;margin-right:4px;opacity:0;transition:opacity 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{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{color:var(--text-primary,#fafafa)}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0}.ai-chat-tool-gear{color:var(--text-primary);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;border-radius:var(--radius-action-badge,3px);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:var(--tool-completed-bg,hsla(0,0%,100%,.12));color:var(--tool-completed-text,hsla(0,0%,100%,.9))}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.completed{--tool-completed-bg:rgba(0,0,0,.08);--tool-completed-text:rgba(0,0,0,.8)}.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}@keyframes ai-chat-gear-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes ai-chat-tool-check-appear{0%{opacity:0;transform:scale(.5)}to{opacity:.7;transform:scale(1)}}.ai-chat-sources{background:rgba(0,0,0,.02);border-radius:6px;font-size:var(--text-xs);margin-top:var(--space-sm);overflow:hidden}.ai-chat-sources-toggle{align-items:center;background:none;border:none;cursor:pointer;display:flex;gap:6px;padding:var(--space-sm) 10px;text-align:left;transition:background var(--duration-fast) ease;width:100%}.ai-chat-sources-toggle:hover{background:rgba(0,0,0,.03)}.ai-chat-sources-icon{color:var(--text-muted);font-size:10px;transition:transform var(--duration-fast) ease}.ai-chat-sources-title{color:var(--text-primary);flex:1;font-size:11px;font-weight:var(--font-weight-semibold);letter-spacing:.5px;text-transform:uppercase}.ai-chat-source-item{border-top:1px solid rgba(0,0,0,.05);color:var(--text-muted);display:flex;gap:var(--space-sm);padding:var(--space-sm) 10px}.ai-chat-source-item:last-child{border-bottom:none}.ai-chat-source-number{color:var(--btn-primary-bg);flex-shrink:0;font-weight:var(--font-weight-semibold)}.ai-chat-source-details{display:flex;flex:1;flex-direction:column;gap:var(--space-xs)}.ai-chat-source-score{color:var(--text-placeholder);font-size:11px}.ai-chat-source-content{color:var(--text-muted);font-size:11px;font-style:italic;line-height:var(--line-height-normal)}.ai-chat-source-metadata{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}.ai-chat-source-meta-item{background:rgba(0,0,0,.05);border-radius:3px;color:var(--text-muted);font-size:10px;padding:2px 6px}";
29122
+ var css_248z = ".ai-chat-widget{--radius-sm:4px;--radius-md:8px;--radius-lg:12px;--radius-xl:16px;--radius-2xl:18px;--radius-pill:9999px;--radius-window-top:22px;--radius-window-bottom:44px;--radius-window-gutter:16px;--radius-chat-bubble:14px;--radius-preset-badge:13px;--radius-history-item:14px;--radius-action-badge: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{--bg-primary:#282625;--bg-secondary:#4a4846;--bg-tertiary:#484848;--bg-hover:#484848;--text-primary:#fff;--text-secondary:#fff;--text-muted:#a1a1aa;--text-placeholder:#71717a;--border-default:#5d5b5b;--border-subtle:#5d5b5b;--border-muted:#5d5b5b;--user-bg:#484848;--user-text:#fff;--user-bg-hover:#5a5a5a;--agent-bg:transparent;--agent-text:#fff;--input-bg:#4a4846;--input-border:#5d5b5b;--input-text:#fff;--btn-primary-bg:#fff;--btn-primary-text:#312f2d;--btn-secondary-bg:transparent;--btn-secondary-text:#a1a1aa;--shadow-window:0px 0px 15px 9px rgba(0,0,0,.2);--shadow-button:0px 0px 15px 9px rgba(0,0,0,.03);--shadow-input:0px 0px 10px rgba(0,0,0,.15)}.ai-chat-widget{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.ai-chat-widget-container{font-size:var(--text-sm);line-height:1.5;position:fixed;z-index:var(--widget-z-index,9999)}.ai-chat-widget-container.bottom-right{bottom:20px;right:20px}.ai-chat-widget-container.bottom-left{bottom:20px;left:20px}.ai-chat-widget-container.top-right{right:20px;top:20px}.ai-chat-widget-container.top-left{left:20px;top:20px}@keyframes windowOpen{0%{opacity:0;transform:scale(.9) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}@keyframes windowClose{0%{opacity:1;transform:scale(1) translateY(0)}to{opacity:0;transform:scale(.9) translateY(20px)}}@keyframes messageSlideIn{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes welcomeFadeIn{0%{opacity:0;transform:translateY(16px)}to{opacity:1;transform:translateY(0)}}@keyframes typingPulse{0%,60%,to{opacity:.4;transform:translateY(0) scale(1)}30%{opacity:1;transform:translateY(-4px) scale(1.1)}}@keyframes ai-chat-tool-active{0%,to{background:var(--bg-secondary);opacity:1}50%{background:var(--bg-tertiary);opacity:1}}@keyframes feedbackMorph{0%{opacity:.5;transform:scale(.8)}to{opacity:1;transform:scale(1)}}@keyframes checkmarkPop{0%{opacity:0;transform:scale(0) rotate(-45deg)}50%{transform:scale(1.3) rotate(0deg)}to{opacity:1;transform:scale(1) rotate(0deg)}}@keyframes ai-chat-history-exit{to{opacity:0;transform:translateY(-18px)}}@media (max-width:480px){.ai-chat-window{animation:mobileSlideUp var(--duration-normal) var(--spring-smooth);border-radius:0!important;bottom:0!important;height:100%!important;left:0!important;position:fixed!important;right:0!important;top:0!important;width:100%!important}@keyframes mobileSlideUp{0%{transform:translateY(100%)}to{transform:translateY(0)}}.ai-chat-header{padding-top:max(16px,env(safe-area-inset-top))}.ai-chat-input-container{padding-bottom:max(20px,env(safe-area-inset-bottom))}}.ai-chat-button{align-items:center;background:var(--button-color,var(--btn-primary-bg));border:1px solid var(--button-border-color,var(--button-color,var(--btn-primary-bg)));border-radius:50%;box-shadow:var(--shadow-button,0 0 15px 9px rgba(0,0,0,.03));color:var(--button-icon-color,var(--btn-primary-text));cursor:pointer;display:flex;height:var(--button-size,56px);justify-content:center;overflow:hidden;position:relative;transition:filter var(--duration-fast) ease,transform var(--duration-fast) ease;width:var(--button-size,56px);z-index:1}.ai-chat-button:hover{transform:scale(1.02)}.ai-chat-button:active{transform:scale(.98)}.ai-chat-button-svg{height:50%;min-height:24px;min-width:24px;transition:transform var(--duration-fast) ease;width:50%}.ai-chat-button.is-open .ai-chat-button-svg{transform:rotate(0deg)}.ai-chat-button-icon{font-size:1.5em;line-height:1}.ai-chat-window{animation:windowOpen var(--duration-slow,.35s) var(--spring-bounce,cubic-bezier(.34,1.56,.64,1));background:var(--bg-primary,#fff);border:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) var(--radius-window-bottom,44px) var(--radius-window-bottom,44px);box-shadow:var(--shadow-window,0 0 15px 5px rgba(0,0,0,.08));display:flex;flex-direction:column;overflow:hidden;position:absolute;transform-origin:bottom right;z-index:2}.ai-chat-widget.dark .ai-chat-window{background:var(--bg-primary,#282625);border-color:var(--border-default,#5d5b5b);border-width:.7px}.ai-chat-window.closing{animation:windowClose var(--duration-normal) var(--spring-smooth) forwards}.ai-chat-window.size-small{height:var(--window-height,580px);width:var(--window-width,380px)}.ai-chat-window.size-medium{height:var(--window-height,720px);width:var(--window-width,440px)}.ai-chat-window.size-large{height:var(--window-height,820px);width:var(--window-width,520px)}.ai-chat-widget-container.bottom-right .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);right:0}.ai-chat-widget-container.bottom-left .ai-chat-window{bottom:calc(var(--button-size, 56px) + 8px);left:0}.ai-chat-widget-container.top-right .ai-chat-window{right:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-widget-container.top-left .ai-chat-window{left:0;top:calc(var(--button-size, 56px) + 8px)}.ai-chat-header{align-items:center;background:var(--bg-primary,#fff);border-bottom:1px solid var(--border-default,#d3d3d3);border-radius:var(--radius-window-top,22px) var(--radius-window-top,22px) 0 0;display:flex;justify-content:space-between;padding:18px var(--space-md,16px);position:relative;z-index:10}.ai-chat-widget.dark .ai-chat-header{background:var(--bg-primary,#282625);border-bottom-color:var(--border-default,#5d5b5b);border-bottom-width:.7px}.ai-chat-header.is-history{padding-left:var(--space-md)}.ai-chat-header.is-history .ai-chat-title{flex:1;min-width:0;overflow:hidden;padding-right:var(--space-lg);text-overflow:ellipsis;white-space:nowrap}.ai-chat-header-content{align-items:center;display:flex;flex:1;gap:var(--space-lg)}.ai-chat-header-actions{align-items:center;display:flex;gap:var(--space-sm)}.ai-chat-logo{border-radius:10px;height:36px;object-fit:cover;width:36px}.ai-chat-title{color:var(--text-primary,#3e3e3e);font-size:var(--text-xl,22px);font-weight:var(--font-weight-bold,700);letter-spacing:-.02em}.ai-chat-widget.dark .ai-chat-title{color:var(--text-primary,#fff)}.ai-chat-close-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-primary);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:color var(--duration-fast) ease;width:32px}.ai-chat-close-button:hover{color:var(--text-muted)}.ai-chat-close-button:active{transform:scale(.95)}.ai-chat-header-button{align-items:center;background:transparent;border:none;border-radius:var(--radius-md);color:var(--text-muted);cursor:pointer;display:flex;height:32px;justify-content:center;padding:0;transition:all var(--duration-fast) ease;width:32px}.ai-chat-header-button:hover{background:var(--bg-secondary);color:var(--text-secondary)}.ai-chat-header-button svg{height:18px;width:18px}.ai-chat-messages{-webkit-overflow-scrolling:touch;-ms-overflow-style:none;align-items:stretch;background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;gap:var(--space-md,16px);justify-content:flex-start;overflow-x:hidden;overflow-y:auto;padding:var(--space-lg,24px) var(--space-md,16px) 100px;position:relative;scroll-behavior:smooth;scrollbar-width:none}.ai-chat-widget.dark .ai-chat-messages{background:var(--bg-primary,#18181b)}.ai-chat-messages::-webkit-scrollbar{display:none}.ai-chat-message{animation:messageSlideIn var(--duration-normal) var(--spring-bounce);display:flex;flex-direction:column;gap:6px}.ai-chat-message-content{word-wrap:break-word;font-size:var(--text-md);line-height:var(--line-height-relaxed);max-width:85%}.ai-chat-message.user{align-items:flex-end}.ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#f4f3f0);border:none;border-radius:var(--radius-chat-bubble,15px);box-shadow:none;color:var(--user-text,#000);padding:var(--space-sm,8px) var(--space-md,16px)}.ai-chat-widget.dark .ai-chat-message.user .ai-chat-message-content{background:var(--user-bg,#484848);color:var(--user-text,#fff)}.ai-chat-message.user .ai-chat-message-meta{justify-content:flex-end;padding-right:var(--space-xs)}.ai-chat-message.assistant{align-items:flex-start}.ai-chat-message.assistant .ai-chat-message-content{background:var(--agent-bg,transparent);border:none;color:var(--agent-text,#18181b);padding:0}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content{color:var(--agent-text,#fafafa)}.ai-chat-message.system{align-items:center}.ai-chat-message.system .ai-chat-message-content{background:hsla(48,96%,89%,.8);border-radius:var(--radius-md);color:#92400e;font-size:var(--text-xs);font-style:italic;max-width:90%;padding:var(--space-sm) var(--space-md);text-align:center}.ai-chat-widget.dark .ai-chat-message.system .ai-chat-message-content{background:rgba(120,53,15,.5);color:#fef3c7}.ai-chat-message.tool{align-items:flex-start}.ai-chat-message.tool .ai-chat-message-content{background:rgba(219,234,254,.8);border-radius:var(--radius-chat-bubble);border-bottom-left-radius:var(--radius-xs);color:#1e40af;font-family:Courier New,monospace;font-size:var(--text-sm);padding:var(--space-sm) var(--space-md)}.ai-chat-widget.dark .ai-chat-message.tool .ai-chat-message-content{background:rgba(30,58,138,.5);color:#dbeafe}.ai-chat-message-meta{align-items:center;color:var(--text-muted);display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding-left:var(--space-xs)}.ai-chat-message-timestamp{font-size:var(--text-xs);line-height:1}.ai-chat-typing{align-items:center;animation:messageSlideIn var(--duration-normal) var(--spring-bounce);background:transparent;display:flex;gap:5px;padding:0}.ai-chat-typing-dot{animation:typingPulse 1.4s ease-in-out infinite;background:var(--text-muted);border-radius:50%;height:6px;width:6px}.ai-chat-typing-dot:nth-child(2){animation-delay:.15s}.ai-chat-typing-dot:nth-child(3){animation-delay:.3s}.ai-chat-welcome{align-items:stretch;animation:welcomeFadeIn var(--duration-slow) var(--spring-smooth);display:flex;flex-direction:column;justify-content:flex-start;padding:0;text-align:left}.ai-chat-welcome-text,.ai-chat-welcome-title{align-self:flex-start}.ai-chat-welcome-title{color:var(--text-primary);font-size:var(--text-2xl);font-weight:var(--font-weight-semibold);letter-spacing:-.02em;margin-bottom:var(--space-md)}.ai-chat-welcome-text{color:var(--text-secondary);font-size:var(--text-md);line-height:var(--line-height-relaxed);max-width:100%}.ai-chat-error{align-items:flex-start;align-self:center;background:var(--bg-secondary);border:none;border-radius:var(--radius-chat-bubble);color:var(--text-primary);display:flex;font-size:var(--text-md);font-weight:var(--font-weight-normal);gap:10px;line-height:1.5;margin:0 auto;max-width:90%;padding:10px var(--space-md)}.ai-chat-error:before{align-items:center;background:rgba(239,68,68,.15);border-radius:50%;color:#ef4444;content:\"⚠\";display:flex;flex-shrink:0;font-size:var(--text-xs);font-weight:700;height:18px;justify-content:center;margin-top:2px;width:18px}.ai-chat-widget.dark .ai-chat-error:before{background:rgba(239,68,68,.2);color:#fca5a5}.ai-chat-message.assistant .ai-chat-message-content p{margin:0 0 12px}.ai-chat-message.assistant .ai-chat-message-content p:last-child{margin-bottom:0}.ai-chat-message.assistant .ai-chat-message-content ol,.ai-chat-message.assistant .ai-chat-message-content ul{margin:8px 0 12px;padding-left:24px}.ai-chat-message.assistant .ai-chat-message-content li{line-height:1.5;margin:6px 0}.ai-chat-message.assistant .ai-chat-message-content strong{font-weight:var(--font-weight-semibold)}.ai-chat-message.assistant .ai-chat-message-content em{font-style:italic}.ai-chat-message.assistant .ai-chat-message-content code{background:rgba(0,0,0,.06);border-radius:var(--radius-sm);font-family:SF Mono,Consolas,Monaco,monospace;font-size:.9em;padding:2px 6px}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content code{background:hsla(0,0%,100%,.1)}.ai-chat-message.assistant .ai-chat-message-content pre{background:rgba(0,0,0,.06);border-radius:var(--radius-md);margin:8px 0 12px;overflow-x:auto;padding:var(--space-sm)}.ai-chat-widget.dark .ai-chat-message.assistant .ai-chat-message-content pre{background:hsla(0,0%,100%,.08)}.ai-chat-message.assistant .ai-chat-message-content pre code{background:transparent;border-radius:0;padding:0}.ai-chat-message.assistant .ai-chat-message-content blockquote{border-left:3px solid var(--btn-primary-bg);color:var(--text-muted);margin:8px 0 12px;padding:4px 0 4px 12px}.ai-chat-message.assistant .ai-chat-message-content a{color:var(--btn-primary-bg);text-decoration:underline}.ai-chat-message.assistant .ai-chat-message-content a:hover{opacity:.8}.ai-chat-message.assistant .ai-chat-message-content h1,.ai-chat-message.assistant .ai-chat-message-content h2,.ai-chat-message.assistant .ai-chat-message-content h3,.ai-chat-message.assistant .ai-chat-message-content h4,.ai-chat-message.assistant .ai-chat-message-content h5,.ai-chat-message.assistant .ai-chat-message-content h6{font-weight:var(--font-weight-semibold);line-height:var(--line-height-tight);margin:16px 0 8px}.ai-chat-message.assistant .ai-chat-message-content h1:first-child,.ai-chat-message.assistant .ai-chat-message-content h2:first-child,.ai-chat-message.assistant .ai-chat-message-content h3:first-child{margin-top:0}.ai-chat-message.assistant .ai-chat-message-content hr{border:none;border-top:1px solid var(--border-subtle);margin:12px 0}.ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#fff) 50%,var(--bg-primary,#fff) 100%);bottom:0;left:0;padding-top:30px;position:absolute;right:0;z-index:10}.ai-chat-widget.dark .ai-chat-input-container{background:linear-gradient(to bottom,transparent 0,var(--bg-primary,#282625) 50%,var(--bg-primary,#282625) 100%)}.ai-chat-input-container.separate{padding:0 var(--radius-window-gutter,16px) var(--radius-window-gutter,16px);padding-top:30px}.ai-chat-input-wrapper{align-items:flex-start;background:var(--input-bg,#f4f4f4);border:1px solid var(--input-border,#d3d3d3);border-radius:var(--radius-input,62px);display:flex;gap:0;height:52px;padding:6px 6px 6px 12px;position:relative;transition:all var(--duration-fast,.15s) ease;z-index:5}.ai-chat-widget.dark .ai-chat-input-wrapper{background:var(--input-bg,#4a4846);border-color:var(--input-border,#5d5b5b);border-width:.7px;box-shadow:var(--shadow-input,0 0 10px rgba(0,0,0,.15))}.ai-chat-input-wrapper:focus-within{border-color:var(--text-muted,#a1a1aa)}.ai-chat-input{word-wrap:break-word;background:transparent;border:none;box-sizing:border-box;color:var(--input-text,#000);flex:1;font-family:inherit;font-size:var(--text-md,15px);height:40px;line-height:20px;max-height:40px;min-height:40px;min-width:0;outline:none;overflow-wrap:anywhere;overflow-x:hidden;overflow-y:auto;padding:10px var(--space-sm,8px);resize:none;white-space:pre-wrap;width:0;word-break:break-word}.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;padding:0;transition:all var(--duration-fast,.15s) ease;width:40px}.ai-chat-widget.dark .ai-chat-send-button{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#151515))));color:var(--button-icon-color,var(--btn-primary-text,#f4f4f4))}.ai-chat-widget.dark .ai-chat-send-button.active{background:var(--send-button-background,var(--primary-color,var(--button-color,var(--btn-primary-bg,#fff))));color:var(--button-icon-color,var(--btn-primary-text,#312f2d))}.ai-chat-send-button:hover:not(:disabled){opacity:.8}.ai-chat-send-button:active:not(:disabled){transform:scale(.95)}.ai-chat-send-button:disabled{cursor:not-allowed;opacity:.3}.ai-chat-file-list{display:flex;flex-wrap:wrap;gap:var(--space-sm);padding:var(--space-sm) var(--space-sm)}.ai-chat-file-item{align-items:center;background:rgba(0,0,0,.05);border-radius:6px;display:flex;font-size:var(--text-xs);gap:var(--space-sm);padding:6px 10px}.ai-chat-file-extension{background:var(--btn-primary-bg);border-radius:3px;color:var(--btn-primary-text);display:inline-block;font-size:10px;font-weight:var(--font-weight-semibold);min-width:40px;padding:2px 6px;text-align:center;text-transform:uppercase}.ai-chat-file-info{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.ai-chat-file-name{font-weight:var(--font-weight-medium);max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-file-size{color:var(--text-muted);font-size:10px;opacity:.7}.ai-chat-file-remove{align-items:center;background:none;border:none;color:inherit;cursor:pointer;display:flex;justify-content:center;opacity:.5;padding:var(--space-xs);transition:opacity var(--duration-fast) ease}.ai-chat-file-remove:hover{opacity:1}.ai-chat-suggested-questions{align-self:flex-end;margin:0;padding:16px 0 0;width:100%}.ai-chat-suggested-questions-list{align-items:center;display:flex;flex-wrap:wrap;gap:6px;justify-content:flex-end}.ai-chat-suggested-question{background:var(--primary-color,var(--button-color,var(--user-bg,#f4f3f0)));border:none;border-radius:var(--radius-preset-badge,13px);color:var(--button-icon-color,var(--user-text,#000));cursor:pointer;font-size:14px;font-weight:400;line-height:1.3;max-width:100%;overflow:hidden;padding:8px 14px;text-overflow:ellipsis;transition:background .15s ease,opacity .15s ease;white-space:nowrap}.ai-chat-widget.dark .ai-chat-suggested-question{background:var(--primary-color,var(--button-color,var(--user-bg,#484848)));color:var(--button-icon-color,var(--user-text,#fff))}.ai-chat-suggested-question-text{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ai-chat-suggested-question:hover{filter:brightness(.9)}.ai-chat-widget.dark .ai-chat-suggested-question:hover{filter:brightness(1.15)}.ai-chat-suggested-question:active{transform:scale(.98)}.ai-chat-suggested-question-icon{display:none}.ai-chat-feedback-buttons{align-items:center;display:flex;gap:var(--space-xs)}.ai-chat-feedback{align-items:center;display:inline-flex;gap:0;height:20px}.ai-chat-feedback-button{align-items:center;background:transparent!important;border:none;border-radius:var(--radius-sm);color:var(--text-placeholder);cursor:pointer;display:flex;font-size:var(--text-sm);height:20px;justify-content:center;padding:var(--space-xs);transition:all var(--duration-fast) var(--spring-bounce)}.ai-chat-feedback-button:hover:not(:disabled){background:none!important;color:var(--text-secondary)}.ai-chat-feedback-button:active:not(:disabled){transform:scale(.9)}.ai-chat-feedback-button:disabled{cursor:not-allowed;opacity:.4}.ai-chat-feedback-button.active{background:none!important;color:var(--text-primary)}.ai-chat-feedback-submitted{align-items:center;animation:feedbackMorph .3s var(--spring-bounce);display:flex;gap:6px}.ai-chat-feedback-checkmark{animation:checkmarkPop .3s var(--spring-bounce);color:#10b981;font-size:var(--text-md);font-weight:700}.ai-chat-feedback-text{color:#10b981;font-size:var(--text-sm);font-weight:var(--font-weight-medium)}.ai-chat-history-panel{background:var(--bg-primary,#fff);display:flex;flex:1;flex-direction:column;overflow:hidden}.ai-chat-widget.dark .ai-chat-history-panel{background:var(--bg-primary,#18181b)}.ai-chat-history-empty,.ai-chat-history-loading{align-items:center;color:var(--text-muted);display:flex;flex:1;font-size:var(--text-sm);justify-content:center;padding:var(--space-lg);text-align:center}.ai-chat-history-list{-ms-overflow-style:none;display:flex;flex:1;flex-direction:column;gap:var(--space-sm);overflow-y:auto;padding:var(--space-md) var(--space-md) 120px;scrollbar-width:none}.ai-chat-history-list::-webkit-scrollbar{display:none}.ai-chat-history-list.exiting{animation:ai-chat-history-exit .22s var(--spring-smooth) forwards}.ai-chat-history-item{align-items: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 3px 0 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;color:var(--text-muted,#71717a);cursor:pointer;display:flex;flex-shrink:0;height:32px;justify-content:center;margin-right:4px;opacity:0;transition:opacity 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{color:var(--text-primary,#18181b)}.ai-chat-widget.dark .ai-chat-history-item-delete:hover{color:var(--text-primary,#fafafa)}.ai-chat-tool-row{align-items:center;display:flex;gap:10px;margin:2px 0}.ai-chat-tool-gear{color:var(--text-primary);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;border-radius:var(--radius-action-badge,3px);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:var(--tool-completed-bg,hsla(0,0%,100%,.12));color:var(--tool-completed-text,hsla(0,0%,100%,.9))}.ai-chat-widget:not(.dark) .ai-chat-tool-badge.completed{--tool-completed-bg:rgba(0,0,0,.08);--tool-completed-text:rgba(0,0,0,.8)}.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}@keyframes ai-chat-gear-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes ai-chat-tool-gradient{0%{background-position:200% 0}to{background-position:-200% 0}}@keyframes ai-chat-tool-check-appear{0%{opacity:0;transform:scale(.5)}to{opacity:.7;transform:scale(1)}}.ai-chat-sources{background:rgba(0,0,0,.02);border-radius:6px;font-size:var(--text-xs);margin-top:var(--space-sm);overflow:hidden}.ai-chat-sources-toggle{align-items:center;background:none;border:none;cursor:pointer;display:flex;gap:6px;padding:var(--space-sm) 10px;text-align:left;transition:background var(--duration-fast) ease;width:100%}.ai-chat-sources-toggle:hover{background:rgba(0,0,0,.03)}.ai-chat-sources-icon{color:var(--text-muted);font-size:10px;transition:transform var(--duration-fast) ease}.ai-chat-sources-title{color:var(--text-primary);flex:1;font-size:11px;font-weight:var(--font-weight-semibold);letter-spacing:.5px;text-transform:uppercase}.ai-chat-source-item{border-top:1px solid rgba(0,0,0,.05);color:var(--text-muted);display:flex;gap:var(--space-sm);padding:var(--space-sm) 10px}.ai-chat-source-item:last-child{border-bottom:none}.ai-chat-source-number{color:var(--btn-primary-bg);flex-shrink:0;font-weight:var(--font-weight-semibold)}.ai-chat-source-details{display:flex;flex:1;flex-direction:column;gap:var(--space-xs)}.ai-chat-source-score{color:var(--text-placeholder);font-size:11px}.ai-chat-source-content{color:var(--text-muted);font-size:11px;font-style:italic;line-height:var(--line-height-normal)}.ai-chat-source-metadata{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px}.ai-chat-source-meta-item{background:rgba(0,0,0,.05);border-radius:3px;color:var(--text-muted);font-size:10px;padding:2px 6px}";
28599
29123
  styleInject(css_248z);
28600
29124
 
28601
29125
  // Icon components mapping
@@ -28699,16 +29223,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
28699
29223
  mediaQuery.removeEventListener('change', handleMediaChange);
28700
29224
  };
28701
29225
  }, [config]);
28702
- // Debug logging
28703
- react.useEffect(() => {
28704
- console.log('[ChatWidget] Config loaded:', config ? 'YES' : 'NO');
28705
- if (config) {
28706
- console.log('[ChatWidget] Config details:', {
28707
- accentColor: config.appearance?.primaryColor,
28708
- autoDetectedTheme,
28709
- });
28710
- }
28711
- }, [config, autoDetectedTheme]);
28712
29226
  // Handle auto-open
28713
29227
  react.useEffect(() => {
28714
29228
  if (config?.settings.autoOpen) {
@@ -28763,17 +29277,8 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
28763
29277
  ...customStyles,
28764
29278
  ...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
28765
29279
  };
28766
- // Debug logging for theme and styles
28767
- react.useEffect(() => {
28768
- console.log('[ChatWidget] Theme info:', {
28769
- effectiveTheme,
28770
- autoDetectedTheme,
28771
- accentColor,
28772
- });
28773
- }, [effectiveTheme, autoDetectedTheme, accentColor]);
28774
29280
  const handleToggle = () => {
28775
29281
  const newState = !isOpen;
28776
- console.log('[ChatWidget] handleToggle called, setting isOpen to:', newState);
28777
29282
  setIsOpen(newState);
28778
29283
  if (newState) {
28779
29284
  onOpen?.();
@@ -28788,10 +29293,8 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
28788
29293
  // Don't render until config is loaded to avoid flash of unstyled content
28789
29294
  // In preview mode, config is always available
28790
29295
  if (!config && !previewMode) {
28791
- console.log('[ChatWidget] Not rendering - config not loaded yet');
28792
29296
  return null;
28793
29297
  }
28794
- console.log('[ChatWidget] Rendering widget', { isOpen, hasConfig: !!config });
28795
29298
  // Get button icon based on state
28796
29299
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
28797
29300
  return (jsxRuntime.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxRuntime.jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition}`, children: [isOpen && (jsxRuntime.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback,