@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.esm.js CHANGED
@@ -1,6 +1,53 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
3
3
 
4
+ async function* parseSSEStream(response, validator) {
5
+ if (!response.body) {
6
+ throw new Error("Response body is null");
7
+ }
8
+ const reader = response.body.getReader();
9
+ const decoder = new TextDecoder();
10
+ let buffer = "";
11
+ try {
12
+ while (true) {
13
+ const { done, value } = await reader.read();
14
+ if (done)
15
+ break;
16
+ buffer += decoder.decode(value, { stream: true });
17
+ const chunks = buffer.split("\n\n");
18
+ buffer = chunks.pop() || "";
19
+ for (const chunk of chunks) {
20
+ const lines = chunk.split("\n");
21
+ for (const line of lines) {
22
+ if (line.startsWith("data: ")) {
23
+ try {
24
+ const data = JSON.parse(line.slice(6));
25
+ if (validator) {
26
+ if (validator(data)) {
27
+ yield data;
28
+ }
29
+ else {
30
+ console.warn("[SSE Parser] Data failed validation:", data);
31
+ }
32
+ }
33
+ else {
34
+ yield data;
35
+ }
36
+ }
37
+ catch (e) {
38
+ console.error("[SSE Parser] Failed to parse SSE data:", line, e);
39
+ throw e;
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ finally {
47
+ reader.releaseLock();
48
+ }
49
+ }
50
+
4
51
  /**
5
52
  * API Client for Widget Communication
6
53
  * Handles all HTTP requests to the widget API
@@ -136,12 +183,8 @@ class WidgetApiClient {
136
183
  const result = await response.json();
137
184
  return result.file;
138
185
  }
139
- /**
140
- * Send a chat message (standard RAG, no actions)
141
- * Returns ConversationMessage[] array
142
- */
143
- async sendMessage(conversationId, message, fileIds) {
144
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/chat`, {
186
+ async *sendAgentMessageStream(conversationId, message, fileIds) {
187
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
145
188
  method: 'POST',
146
189
  headers: {
147
190
  'Content-Type': 'application/json',
@@ -154,167 +197,36 @@ class WidgetApiClient {
154
197
  }),
155
198
  });
156
199
  if (!response.ok) {
157
- throw await buildApiError(response, 'Failed to send message');
158
- }
159
- return response.json();
160
- }
161
- /**
162
- * Send a message to agent (with actions support)
163
- */
164
- async sendAgentMessage(conversationId, message, fileIds) {
165
- try {
166
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
167
- method: 'POST',
168
- headers: {
169
- 'Content-Type': 'application/json',
170
- },
171
- body: JSON.stringify({
172
- conversationId: conversationId,
173
- message,
174
- fileIds,
175
- timeZone: this.getTimeZone(),
176
- }),
177
- });
178
- if (!response.ok) {
179
- throw await buildApiError(response, `Agent request failed with status ${response.status}`);
180
- }
181
- const data = await response.json();
182
- // Check if response indicates an error
183
- if (data.type === 'error') {
184
- throw new Error(data.message || 'Agent encountered an error');
185
- }
186
- return data;
187
- }
188
- catch (error) {
189
- // Enhance error messages
190
- if (error instanceof TypeError && error.message.includes('fetch')) {
191
- throw new ApiError('Network error: Unable to reach the server', 0);
192
- }
193
- throw error;
200
+ throw await buildApiError(response, 'Failed to send agent message');
194
201
  }
195
- }
196
- /**
197
- * Stream chat message responses
198
- */
199
- async *sendMessageStream(conversationId, message, fileIds) {
200
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/chat`, {
201
- method: 'POST',
202
- headers: {
203
- 'Content-Type': 'application/json',
204
- },
205
- body: JSON.stringify({
206
- conversationId: conversationId,
207
- message,
208
- fileIds,
209
- timeZone: this.getTimeZone(),
210
- }),
202
+ yield* parseSSEStream(response, (data) => {
203
+ return typeof data === 'object' && data !== null && 'type' in data;
211
204
  });
212
- if (!response.ok) {
213
- throw await buildApiError(response, 'Failed to send message');
214
- }
215
- if (!response.body) {
216
- throw new Error('Response body is null');
217
- }
218
- const reader = response.body.getReader();
219
- const decoder = new TextDecoder();
220
- let buffer = '';
221
- try {
222
- while (true) {
223
- const { done, value } = await reader.read();
224
- if (done)
225
- break;
226
- buffer += decoder.decode(value, { stream: true });
227
- const lines = buffer.split('\n');
228
- buffer = lines.pop() || '';
229
- for (const line of lines) {
230
- if (line.startsWith('data: ')) {
231
- try {
232
- const data = JSON.parse(line.slice(6));
233
- // Handle error events
234
- if (data.type === 'error') {
235
- throw new Error(data.error || 'Stream error');
236
- }
237
- // Yield ConversationMessage objects
238
- if (data.id) {
239
- yield data;
240
- }
241
- }
242
- catch (e) {
243
- console.error('[Widget API Client] Failed to parse SSE data:', line, e);
244
- throw e;
245
- }
246
- }
247
- }
248
- }
249
- }
250
- finally {
251
- reader.releaseLock();
252
- }
253
205
  }
254
- /**
255
- * Stream agent message responses with tool execution
256
- * Handles streaming events from backend and yields ConversationMessage updates
257
- */
258
- async *sendAgentMessageStream(conversationId, message, fileIds) {
259
- const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
206
+ async *continueAgentMessageStream(conversationId, toolCallId, state) {
207
+ const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
260
208
  method: 'POST',
261
209
  headers: {
262
210
  'Content-Type': 'application/json',
263
211
  },
264
212
  body: JSON.stringify({
265
213
  conversationId: conversationId,
266
- message,
267
- fileIds,
214
+ toolCallId,
215
+ state,
268
216
  timeZone: this.getTimeZone(),
269
217
  }),
270
218
  });
271
219
  if (!response.ok) {
272
- throw await buildApiError(response, 'Failed to send agent message');
273
- }
274
- if (!response.body) {
275
- throw new Error('Response body is null');
276
- }
277
- const reader = response.body.getReader();
278
- const decoder = new TextDecoder();
279
- let buffer = '';
280
- try {
281
- while (true) {
282
- const { done, value } = await reader.read();
283
- if (done)
284
- break;
285
- buffer += decoder.decode(value, { stream: true });
286
- const lines = buffer.split('\n');
287
- buffer = lines.pop() || '';
288
- for (const line of lines) {
289
- if (line.startsWith('data: ')) {
290
- try {
291
- const data = JSON.parse(line.slice(6));
292
- // Handle error events
293
- if (data.type === 'error') {
294
- throw new Error(data.error || 'Stream error');
295
- }
296
- // Yield ConversationMessage objects that come from the backend
297
- // The backend yields full ConversationMessage objects during streaming
298
- if (data.id) {
299
- yield data;
300
- }
301
- }
302
- catch (e) {
303
- console.error('[Widget API Client] Failed to parse SSE data:', line, e);
304
- throw e;
305
- }
306
- }
307
- }
308
- }
309
- }
310
- finally {
311
- reader.releaseLock();
220
+ throw await buildApiError(response, 'Failed to continue agent');
312
221
  }
222
+ yield* parseSSEStream(response, (data) => {
223
+ return typeof data === 'object' && data !== null && 'type' in data;
224
+ });
313
225
  }
314
226
  /**
315
227
  * Submit feedback for a message
316
228
  */
317
- async submitFeedback(sessionId, messageId, feedback) {
229
+ async submitFeedback(sessionId, messageId, feedback, meta) {
318
230
  const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/feedback`, {
319
231
  method: 'POST',
320
232
  headers: {
@@ -324,6 +236,9 @@ class WidgetApiClient {
324
236
  conversationId: sessionId,
325
237
  messageId: messageId,
326
238
  feedback,
239
+ messageRole: meta?.role,
240
+ messageContent: meta?.content,
241
+ messageTimestamp: meta?.timestamp,
327
242
  }),
328
243
  });
329
244
  if (!response.ok) {
@@ -374,6 +289,173 @@ function generateMessageId() {
374
289
  return `msg_${timestamp}_${randomStr}`;
375
290
  }
376
291
 
292
+ const pendingResolvers = new Map();
293
+ const resumeCallbacks = new Map();
294
+ const frontendActionHandlers = {};
295
+ const actionRenderers = {};
296
+ function getFrontendActionHandler(implementation) {
297
+ return frontendActionHandlers[implementation];
298
+ }
299
+ function getActionRenderer(implementation) {
300
+ return actionRenderers[implementation];
301
+ }
302
+ function getActionPrompt(implementation) {
303
+ if (implementation === "google-calendar-appointment") {
304
+ return "Select a date to continue.";
305
+ }
306
+ return "Action input required.";
307
+ }
308
+ function waitForActionState(toolCallId) {
309
+ return new Promise((resolve) => {
310
+ pendingResolvers.set(toolCallId, resolve);
311
+ });
312
+ }
313
+ function resolveActionState(toolCallId, state) {
314
+ const resolver = pendingResolvers.get(toolCallId);
315
+ if (resolver) {
316
+ pendingResolvers.delete(toolCallId);
317
+ resolver(state);
318
+ return;
319
+ }
320
+ // If no active resolver, check for a resume callback (for page reload scenario)
321
+ const resumeCallback = resumeCallbacks.get(toolCallId);
322
+ if (resumeCallback) {
323
+ resumeCallback(state).catch((error) => {
324
+ console.error("[Action] Failed to resume action:", error);
325
+ });
326
+ }
327
+ }
328
+ function registerActionResumeCallback(toolCallId, callback) {
329
+ resumeCallbacks.set(toolCallId, callback);
330
+ }
331
+ function unregisterActionResumeCallback(toolCallId) {
332
+ resumeCallbacks.delete(toolCallId);
333
+ }
334
+
335
+ function groupSlotsByDate(slots) {
336
+ const grouped = new Map();
337
+ for (const slot of slots) {
338
+ if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
339
+ continue;
340
+ }
341
+ const date = slot.startTime.slice(0, 10);
342
+ if (!grouped.has(date)) {
343
+ grouped.set(date, []);
344
+ }
345
+ grouped.get(date).push(slot);
346
+ }
347
+ return grouped;
348
+ }
349
+ function formatDate(dateStr) {
350
+ try {
351
+ const date = new Date(dateStr);
352
+ return new Intl.DateTimeFormat("en-US", {
353
+ weekday: "short",
354
+ month: "short",
355
+ day: "numeric",
356
+ }).format(date);
357
+ }
358
+ catch {
359
+ return dateStr;
360
+ }
361
+ }
362
+ function GoogleCalendarAppointmentCard({ message }) {
363
+ const action = message.action;
364
+ if (!action || action.implementation !== "google-calendar-appointment") {
365
+ return null;
366
+ }
367
+ const rawSlots = action.state.availableSlots;
368
+ const availableSlots = Array.isArray(rawSlots)
369
+ ? rawSlots.filter((slot) => slot !== null &&
370
+ slot !== undefined &&
371
+ typeof slot === "object" &&
372
+ "startTime" in slot &&
373
+ "endTime" in slot &&
374
+ typeof slot.startTime === "string" &&
375
+ typeof slot.endTime === "string")
376
+ : [];
377
+ const allowTopic = action.state.allowTopic !== false;
378
+ const isBooked = action.state.status === "booked";
379
+ const slotsByDate = groupSlotsByDate(availableSlots);
380
+ const dates = Array.from(slotsByDate.keys()).sort();
381
+ const [selectedDate, setSelectedDate] = useState(dates[0] ?? "");
382
+ const [selectedSlot, setSelectedSlot] = useState(null);
383
+ const [topic, setTopic] = useState("");
384
+ const [error, setError] = useState(null);
385
+ const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
386
+ const onConfirm = () => {
387
+ if (!selectedSlot) {
388
+ setError("Please select a time slot.");
389
+ return;
390
+ }
391
+ if (allowTopic && !topic.trim()) {
392
+ setError("Please enter a topic for the meeting.");
393
+ return;
394
+ }
395
+ setError(null);
396
+ resolveActionState(action.toolCallId, {
397
+ ...action.state,
398
+ selectedSlot: {
399
+ startTime: selectedSlot.startTime,
400
+ endTime: selectedSlot.endTime,
401
+ },
402
+ topic: allowTopic ? topic.trim() : null,
403
+ });
404
+ };
405
+ if (isBooked) {
406
+ const rawBookedSlot = action.state.selectedSlot;
407
+ const bookedSlot = rawBookedSlot &&
408
+ typeof rawBookedSlot === "object" &&
409
+ "startTime" in rawBookedSlot &&
410
+ "endTime" in rawBookedSlot
411
+ ? rawBookedSlot
412
+ : null;
413
+ const bookedTopic = typeof action.state.topic === "string" ? action.state.topic : null;
414
+ const eventLink = typeof action.state.bookedEventLink === "string" ? action.state.bookedEventLink : null;
415
+ return (jsxs("div", { className: "ai-chat-action-card ai-chat-action-booked", children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: 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"] }), jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxs("div", { className: "ai-chat-action-detail", children: [jsx("span", { className: "ai-chat-action-label", children: "Topic:" }), jsx("span", { className: "ai-chat-action-value", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxs("div", { className: "ai-chat-action-detail", children: [jsx("span", { className: "ai-chat-action-label", children: "Time:" }), jsx("span", { className: "ai-chat-action-value", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsx("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link", children: "View in Google Calendar \u2192" }))] })] }));
416
+ }
417
+ return (jsxs("div", { className: "ai-chat-action-card", children: [jsxs("div", { className: "ai-chat-action-header", children: [jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsx("path", { fillRule: "evenodd", d: "M6 2a1 1 0 00-1 1v1H4a2 2 0 00-2 2v10a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2h-1V3a1 1 0 10-2 0v1H7V3a1 1 0 00-1-1zm0 5a1 1 0 000 2h8a1 1 0 100-2H6z", clipRule: "evenodd" }) }), "Schedule an Appointment"] }), jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsx("input", { id: `topic-${action.toolCallId}`, type: "text", className: "ai-chat-action-input", placeholder: "e.g., Product Demo", value: topic, onChange: (e) => setTopic(e.target.value) })] })), jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
418
+ setSelectedDate(date);
419
+ setSelectedSlot(null);
420
+ }, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxs("div", { className: "ai-chat-action-field", children: [jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsx("button", { type: "button", className: `ai-chat-action-time-btn ${selectedSlot?.startTime === slot.startTime ? "active" : ""}`, onClick: () => setSelectedSlot(slot), children: slot.displayTime || new Date(slot.startTime).toLocaleTimeString([], { hour: "numeric", minute: "2-digit" }) }, slot.startTime))) })] })), error && jsx("div", { className: "ai-chat-action-error", children: error }), jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
421
+ }
422
+
423
+ frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
424
+ return waitForActionState(context.toolCallId);
425
+ };
426
+
427
+ function styleInject(css, ref) {
428
+ if ( ref === void 0 ) ref = {};
429
+ var insertAt = ref.insertAt;
430
+
431
+ if (!css || typeof document === 'undefined') { return; }
432
+
433
+ var head = document.head || document.getElementsByTagName('head')[0];
434
+ var style = document.createElement('style');
435
+ style.type = 'text/css';
436
+
437
+ if (insertAt === 'top') {
438
+ if (head.firstChild) {
439
+ head.insertBefore(style, head.firstChild);
440
+ } else {
441
+ head.appendChild(style);
442
+ }
443
+ } else {
444
+ head.appendChild(style);
445
+ }
446
+
447
+ if (style.styleSheet) {
448
+ style.styleSheet.cssText = css;
449
+ } else {
450
+ style.appendChild(document.createTextNode(css));
451
+ }
452
+ }
453
+
454
+ 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)}";
455
+ styleInject(css_248z$1);
456
+
457
+ actionRenderers["google-calendar-appointment"] = (message) => (jsx(GoogleCalendarAppointmentCard, { message: message }));
458
+
377
459
  /**
378
460
  * Local Storage Utilities
379
461
  * Handles conversation persistence in browser localStorage
@@ -435,9 +517,12 @@ function setWidgetStorage(widgetId, storage) {
435
517
  * Get preview text from messages
436
518
  */
437
519
  function getConversationPreview(messages) {
438
- const firstUserMessage = messages.find(m => m.message.type === 'human');
520
+ const firstUserMessage = messages.find(m => m.message.role === "user");
439
521
  if (firstUserMessage) {
440
- return firstUserMessage.message.content.slice(0, 100);
522
+ const content = typeof firstUserMessage.message.content === "string"
523
+ ? firstUserMessage.message.content
524
+ : "";
525
+ return content.slice(0, 100);
441
526
  }
442
527
  return 'New conversation';
443
528
  }
@@ -592,6 +677,473 @@ function isStorageAvailable() {
592
677
  * useChat Hook
593
678
  * Main state management for chat functionality
594
679
  */
680
+ function hydrateToolNames(messages) {
681
+ const toolCallNameById = new Map();
682
+ for (const entry of messages) {
683
+ if (entry.message.role !== "assistant") {
684
+ continue;
685
+ }
686
+ const toolCalls = entry.message.tool_calls;
687
+ if (!Array.isArray(toolCalls)) {
688
+ continue;
689
+ }
690
+ for (const call of toolCalls) {
691
+ const callId = call?.id;
692
+ const callName = call?.function?.name;
693
+ if (callId && callName) {
694
+ toolCallNameById.set(callId, callName);
695
+ }
696
+ }
697
+ }
698
+ if (toolCallNameById.size === 0) {
699
+ return messages;
700
+ }
701
+ return messages.map((entry) => {
702
+ if (entry.message.role !== "tool") {
703
+ return entry;
704
+ }
705
+ const toolCallId = entry.message.tool_call_id;
706
+ const resolvedName = toolCallNameById.get(toolCallId);
707
+ if (!resolvedName) {
708
+ return entry;
709
+ }
710
+ const currentName = entry.message.name;
711
+ const nextName = currentName && currentName.trim().length > 0 ? currentName : resolvedName;
712
+ const nextToolExecuting = entry.toolExecuting || resolvedName;
713
+ if (nextName === currentName && nextToolExecuting === entry.toolExecuting) {
714
+ return entry;
715
+ }
716
+ return {
717
+ ...entry,
718
+ message: { ...entry.message, name: nextName },
719
+ toolExecuting: nextToolExecuting,
720
+ };
721
+ });
722
+ }
723
+ function hydrateActionContent(messages) {
724
+ return messages.map((entry) => {
725
+ if (entry.message.role !== "assistant" || !entry.action) {
726
+ return entry;
727
+ }
728
+ const content = typeof entry.message.content === "string" ? entry.message.content : "";
729
+ if (content.trim().length > 0) {
730
+ return entry;
731
+ }
732
+ return {
733
+ ...entry,
734
+ message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
735
+ };
736
+ });
737
+ }
738
+ function hydrateMessages(messages) {
739
+ return hydrateActionContent(hydrateToolNames(messages));
740
+ }
741
+ function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
742
+ // Find all incomplete actions and register resume callbacks
743
+ for (const message of messages) {
744
+ if (message.action && !message.action.done) {
745
+ const toolCallId = message.action.toolCallId;
746
+ const toolName = message.message.name || message.toolExecuting || "tool";
747
+ registerActionResumeCallback(toolCallId, async (newState) => {
748
+ // When user interacts with the action after reload, continue the stream
749
+ try {
750
+ // Update the action message with the new state
751
+ setState(prev => ({
752
+ ...prev,
753
+ messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
754
+ ? {
755
+ ...m,
756
+ action: m.action ? { ...m.action, state: newState } : undefined,
757
+ }
758
+ : m),
759
+ isTyping: true,
760
+ }));
761
+ const streamState = createStreamState();
762
+ // Continue the agent stream with the new state
763
+ for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
764
+ if (event.type === "done") {
765
+ finalizeToolMessage(streamState, setState, toolCallId, toolName);
766
+ streamState.sources = event.sources;
767
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
768
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
769
+ continue;
770
+ }
771
+ if (event.type === "error") {
772
+ const errorMessage = {
773
+ id: generateMessageId(),
774
+ message: {
775
+ role: "assistant",
776
+ content: `Error: ${event.error}`,
777
+ },
778
+ timestamp: new Date().toISOString(),
779
+ sources: [],
780
+ isError: true,
781
+ };
782
+ upsertMessage(setState, errorMessage, false);
783
+ setState(prev => ({ ...prev, isTyping: false }));
784
+ return;
785
+ }
786
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
787
+ }
788
+ setState(prev => ({ ...prev, isTyping: false }));
789
+ }
790
+ catch (error) {
791
+ console.error("[Action Resume] Failed to continue stream:", error);
792
+ setState(prev => ({ ...prev, isTyping: false, error: error instanceof Error ? error.message : "Failed to resume action" }));
793
+ throw error;
794
+ }
795
+ });
796
+ }
797
+ }
798
+ }
799
+ function createStreamState() {
800
+ return {
801
+ currentContent: "",
802
+ currentMessageId: generateMessageId(),
803
+ activeToolCallCount: 0,
804
+ newMessageIds: new Set(),
805
+ sources: [],
806
+ toolCallToActionId: {},
807
+ };
808
+ }
809
+ function upsertMessage(setState, message, isTyping) {
810
+ setState(prev => {
811
+ const existingIndex = prev.messages.findIndex(m => m.id === message.id);
812
+ if (existingIndex >= 0) {
813
+ const newMessages = [...prev.messages];
814
+ newMessages[existingIndex] = message;
815
+ return { ...prev, messages: newMessages, isTyping, isLoading: false };
816
+ }
817
+ return {
818
+ ...prev,
819
+ messages: [...prev.messages, message],
820
+ isTyping,
821
+ isLoading: false,
822
+ };
823
+ });
824
+ }
825
+ function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionId) {
826
+ setState(prev => ({
827
+ ...prev,
828
+ messages: prev.messages.map(msg => (messageIds.has(msg.id)
829
+ ? { ...msg, sources, toolCallToActionId }
830
+ : msg)),
831
+ isTyping: false,
832
+ }));
833
+ }
834
+ function handleContentEvent(event, streamState, onMessageUpdate, setState) {
835
+ streamState.currentContent += event.content;
836
+ const assistantMessage = {
837
+ id: streamState.currentMessageId,
838
+ message: { role: "assistant", content: streamState.currentContent },
839
+ timestamp: new Date().toISOString(),
840
+ sources: streamState.sources,
841
+ isStreaming: true,
842
+ };
843
+ streamState.newMessageIds.add(assistantMessage.id);
844
+ onMessageUpdate(assistantMessage);
845
+ const hasContent = assistantMessage.message.content?.trim().length || 0 > 0;
846
+ const isToolExecuting = streamState.activeToolCallCount > 0;
847
+ const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
848
+ upsertMessage(setState, assistantMessage, isTyping);
849
+ }
850
+ function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
851
+ if (streamState.currentContent.trim()) {
852
+ const finalAssistant = {
853
+ id: streamState.currentMessageId,
854
+ message: { role: "assistant", content: streamState.currentContent },
855
+ timestamp: new Date().toISOString(),
856
+ sources: streamState.sources,
857
+ isStreaming: false,
858
+ };
859
+ streamState.newMessageIds.add(finalAssistant.id);
860
+ onMessageUpdate(finalAssistant);
861
+ upsertMessage(setState, finalAssistant, true);
862
+ streamState.currentContent = "";
863
+ streamState.currentMessageId = generateMessageId();
864
+ }
865
+ const toolMessageId = event.tool_call_id;
866
+ streamState.activeToolCallCount += 1;
867
+ streamState.newMessageIds.add(toolMessageId);
868
+ const toolMessage = {
869
+ id: toolMessageId,
870
+ sources: [],
871
+ message: { role: "tool", content: "", tool_call_id: event.tool_call_id, name: event.tool_name },
872
+ timestamp: new Date().toISOString(),
873
+ isStreaming: true,
874
+ toolExecuting: event.tool_name,
875
+ };
876
+ upsertMessage(setState, toolMessage, true);
877
+ }
878
+ function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
879
+ // Update state and mark action as done in a single setState call
880
+ setState(prev => {
881
+ const messages = prev.messages.map((msg) => {
882
+ const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
883
+ if (!matchesToolCall) {
884
+ return msg;
885
+ }
886
+ const existingName = msg.message.name || event.tool_name;
887
+ return {
888
+ ...msg,
889
+ message: {
890
+ role: "tool",
891
+ content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
892
+ tool_call_id: event.tool_call_id,
893
+ name: existingName,
894
+ },
895
+ isStreaming: false,
896
+ toolExecuting: existingName,
897
+ action: msg.action ? {
898
+ ...msg.action,
899
+ state: event.state || msg.action.state,
900
+ done: true, // Mark action as completed
901
+ } : undefined,
902
+ };
903
+ });
904
+ return { ...prev, messages, isTyping: false, isLoading: false };
905
+ });
906
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
907
+ }
908
+ function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
909
+ setState(prev => {
910
+ const messages = prev.messages.map((entry) => {
911
+ const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === event.tool_call_id;
912
+ if (!matchesToolCall) {
913
+ return entry;
914
+ }
915
+ const name = entry.message.name || "tool";
916
+ const toolMessage = {
917
+ ...entry,
918
+ message: {
919
+ role: "tool",
920
+ content: event.error || "Tool execution failed",
921
+ tool_call_id: event.tool_call_id,
922
+ name,
923
+ },
924
+ timestamp: new Date().toISOString(),
925
+ isStreaming: false,
926
+ isError: true,
927
+ toolExecuting: name,
928
+ };
929
+ return toolMessage;
930
+ });
931
+ return { ...prev, messages, isTyping: false, isLoading: false };
932
+ });
933
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
934
+ }
935
+ function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
936
+ setState(prev => {
937
+ const messages = prev.messages.map((entry) => {
938
+ const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
939
+ if (!matchesToolCall) {
940
+ return entry;
941
+ }
942
+ const existingName = entry.message.name || toolName;
943
+ return {
944
+ ...entry,
945
+ message: {
946
+ role: "tool",
947
+ content: typeof entry.message.content === "string" ? entry.message.content : "",
948
+ tool_call_id: toolCallId,
949
+ name: existingName,
950
+ },
951
+ isStreaming: false,
952
+ toolExecuting: existingName,
953
+ action: entry.action ? {
954
+ ...entry.action,
955
+ done: true, // Mark action as completed
956
+ } : undefined,
957
+ };
958
+ });
959
+ return { ...prev, messages, isTyping: false, isLoading: false };
960
+ });
961
+ streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
962
+ }
963
+ function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
964
+ streamState.sources = event.sources;
965
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
966
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
967
+ }
968
+ function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
969
+ const toolNames = event.tool_calls.map(call => call.name).join(", ");
970
+ const notice = toolNames
971
+ ? `Awaiting external tool results: ${toolNames}.`
972
+ : "Awaiting external tool results.";
973
+ const haltMessage = {
974
+ id: generateMessageId(),
975
+ message: { role: "assistant", content: notice },
976
+ timestamp: new Date().toISOString(),
977
+ sources: [],
978
+ isError: true,
979
+ };
980
+ onMessageUpdate(haltMessage);
981
+ upsertMessage(setState, haltMessage, false);
982
+ setState(prev => ({ ...prev, error: "Awaiting external tool handling." }));
983
+ }
984
+ function handleErrorEvent(event, _streamState, onMessageUpdate, setState) {
985
+ const errorMessage = {
986
+ id: generateMessageId(),
987
+ message: { role: "assistant", content: `⚠️ ${event.error}` },
988
+ timestamp: new Date().toISOString(),
989
+ sources: [],
990
+ isError: true,
991
+ };
992
+ onMessageUpdate(errorMessage);
993
+ upsertMessage(setState, errorMessage, false);
994
+ setState(prev => ({ ...prev, error: event.error }));
995
+ }
996
+ const eventHandlers = {
997
+ content: handleContentEvent,
998
+ tool_start: handleToolStartEvent,
999
+ tool_end: handleToolEndEvent,
1000
+ tool_error: handleToolErrorEvent,
1001
+ done: handleDoneEvent,
1002
+ halt: handleHaltEvent,
1003
+ error: handleErrorEvent,
1004
+ action_request: () => { },
1005
+ };
1006
+ function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
1007
+ if (event.type === "tool_start" || event.type === "tool_end" || event.type === "tool_error" || event.type === "action_request" || event.type === "done" || event.type === "halt") {
1008
+ console.log("[Widget] stream event:", {
1009
+ type: event.type,
1010
+ toolCallId: "tool_call_id" in event ? event.tool_call_id : undefined,
1011
+ toolName: "tool_name" in event ? event.tool_name : undefined,
1012
+ });
1013
+ }
1014
+ const handler = eventHandlers[event.type];
1015
+ if (handler) {
1016
+ handler(event, streamState, onMessageUpdate, setState);
1017
+ }
1018
+ else {
1019
+ console.warn('[Chat] Unknown event type:', event.type);
1020
+ }
1021
+ }
1022
+ async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
1023
+ let pendingEvent = initialEvent;
1024
+ while (pendingEvent) {
1025
+ streamState.toolCallToActionId = pendingEvent.tool_call_to_action_id;
1026
+ const resumeToolCallId = pendingEvent.tool_call_id;
1027
+ const existingToolMessage = getMessages().find((entry) => entry.message.role === "tool" && entry.message.tool_call_id === resumeToolCallId);
1028
+ const toolMessageId = existingToolMessage?.id ?? resumeToolCallId;
1029
+ const toolName = existingToolMessage?.message.name ?? "tool";
1030
+ const toolMessage = {
1031
+ id: toolMessageId,
1032
+ sources: [],
1033
+ message: {
1034
+ role: "tool",
1035
+ content: "",
1036
+ tool_call_id: resumeToolCallId,
1037
+ name: toolName,
1038
+ },
1039
+ timestamp: new Date().toISOString(),
1040
+ isStreaming: true,
1041
+ toolExecuting: toolName,
1042
+ action: {
1043
+ implementation: pendingEvent.implementation,
1044
+ toolCallId: pendingEvent.tool_call_id,
1045
+ actionId: pendingEvent.action_id,
1046
+ input: pendingEvent.input,
1047
+ state: pendingEvent.state,
1048
+ done: false, // Action not yet completed
1049
+ },
1050
+ };
1051
+ if (streamState.activeToolCallCount === 0) {
1052
+ streamState.activeToolCallCount = 1;
1053
+ }
1054
+ onMessageUpdate(toolMessage);
1055
+ upsertMessage(setState, toolMessage, true);
1056
+ const handler = getFrontendActionHandler(pendingEvent.implementation);
1057
+ if (!handler) {
1058
+ const errorMessage = {
1059
+ id: generateMessageId(),
1060
+ message: {
1061
+ role: "assistant",
1062
+ content: `⚠️ No frontend handler for action '${pendingEvent.implementation}'.`,
1063
+ },
1064
+ timestamp: new Date().toISOString(),
1065
+ sources: [],
1066
+ isError: true,
1067
+ };
1068
+ onMessageUpdate(errorMessage);
1069
+ upsertMessage(setState, errorMessage, false);
1070
+ setState(prev => ({ ...prev, error: `Missing frontend handler: ${pendingEvent?.implementation}` }));
1071
+ return;
1072
+ }
1073
+ let nextState;
1074
+ try {
1075
+ nextState = await handler(pendingEvent.input, pendingEvent.state, {
1076
+ widgetId,
1077
+ conversationId,
1078
+ toolCallId: pendingEvent.tool_call_id,
1079
+ actionId: pendingEvent.action_id,
1080
+ implementation: pendingEvent.implementation,
1081
+ });
1082
+ }
1083
+ catch (error) {
1084
+ const errorMessage = error instanceof Error ? error.message : "Frontend action failed.";
1085
+ const errorMessageEntry = {
1086
+ id: generateMessageId(),
1087
+ message: { role: "assistant", content: `⚠️ ${errorMessage}` },
1088
+ timestamp: new Date().toISOString(),
1089
+ sources: [],
1090
+ isError: true,
1091
+ };
1092
+ onMessageUpdate(errorMessageEntry);
1093
+ upsertMessage(setState, errorMessageEntry, false);
1094
+ setState(prev => ({ ...prev, error: errorMessage }));
1095
+ return;
1096
+ }
1097
+ pendingEvent = null;
1098
+ const updatedToolMessage = {
1099
+ ...toolMessage,
1100
+ action: toolMessage.action
1101
+ ? {
1102
+ ...toolMessage.action,
1103
+ state: nextState,
1104
+ }
1105
+ : undefined,
1106
+ };
1107
+ upsertMessage(setState, updatedToolMessage, true);
1108
+ let streamEnded = false;
1109
+ for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
1110
+ if (event.type === "action_request") {
1111
+ pendingEvent = event;
1112
+ break;
1113
+ }
1114
+ if (event.type === "done") {
1115
+ // Don't extract and update state from done event - the state was already
1116
+ // updated by tool_end event or by the user's frontend action.
1117
+ finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
1118
+ // Handle the done event but skip the tool finalization part since we already did it
1119
+ streamState.sources = event.sources;
1120
+ streamState.toolCallToActionId = event.tool_call_to_action_id;
1121
+ finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
1122
+ streamEnded = true;
1123
+ continue; // Skip handleStreamEvent for done events to avoid state conflicts
1124
+ }
1125
+ if (event.type === "error") {
1126
+ const errorMessage = {
1127
+ id: generateMessageId(),
1128
+ message: {
1129
+ role: "assistant",
1130
+ content: `Error occurred during action execution: ${event.error}`,
1131
+ },
1132
+ timestamp: new Date().toISOString(),
1133
+ sources: [],
1134
+ isError: true,
1135
+ };
1136
+ upsertMessage(setState, errorMessage, false);
1137
+ return;
1138
+ }
1139
+ handleStreamEvent(event, streamState, onMessageUpdate, setState);
1140
+ }
1141
+ // If stream ended without a done event (e.g., only tool_end was sent), finalize the tool message
1142
+ if (!streamEnded && !pendingEvent) {
1143
+ finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
1144
+ }
1145
+ }
1146
+ }
595
1147
  function deriveErrorInfo(error) {
596
1148
  if (error instanceof ApiError) {
597
1149
  const retryAfterSeconds = typeof error.retryAfterMs === 'number'
@@ -664,6 +1216,10 @@ function useChat(options) {
664
1216
  conversationId: '', // Will be set after loading conversation
665
1217
  config: null,
666
1218
  });
1219
+ const stateRef = useRef(state);
1220
+ useEffect(() => {
1221
+ stateRef.current = state;
1222
+ }, [state]);
667
1223
  // Chat history state
668
1224
  const [conversations, setConversations] = useState([]);
669
1225
  const apiClient = useRef(new WidgetApiClient({ widgetId, apiUrl }));
@@ -671,18 +1227,12 @@ function useChat(options) {
671
1227
  useEffect(() => {
672
1228
  // Skip initialization in preview mode
673
1229
  if (skipInitialization) {
674
- console.log('[useChat] Skipping initialization (preview mode)');
675
1230
  return;
676
1231
  }
677
1232
  let isMounted = true;
678
- console.log('[useChat] Effect running, mounting component');
679
1233
  const initialize = async () => {
680
1234
  try {
681
- console.log('[useChat] Fetching config...');
682
1235
  const config = await apiClient.current.getConfig();
683
- console.log('[useChat] Config fetched successfully:', {
684
- hasAppearance: !!config.appearance,
685
- });
686
1236
  const persistConversation = config.settings.persistConversation ?? true;
687
1237
  let conversationId = '';
688
1238
  let messages = [];
@@ -693,7 +1243,7 @@ function useChat(options) {
693
1243
  try {
694
1244
  const conversation = await apiClient.current.getOrCreateConversation(storedId);
695
1245
  conversationId = conversation.id;
696
- messages = conversation.messages;
1246
+ messages = hydrateMessages(conversation.messages);
697
1247
  }
698
1248
  catch (conversationError) {
699
1249
  console.warn('Failed to load existing conversation:', conversationError);
@@ -701,16 +1251,19 @@ function useChat(options) {
701
1251
  }
702
1252
  }
703
1253
  if (!isMounted) {
704
- console.log('[useChat] Component unmounted, skipping state update');
705
1254
  return;
706
1255
  }
707
- console.log('[useChat] Setting config in state');
1256
+ const hydratedMessages = hydrateMessages(messages);
708
1257
  setState(prev => ({
709
1258
  ...prev,
710
1259
  config,
711
1260
  conversationId,
712
- messages,
1261
+ messages: hydratedMessages,
713
1262
  }));
1263
+ // Setup resume callbacks for incomplete actions
1264
+ if (conversationId) {
1265
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
1266
+ }
714
1267
  }
715
1268
  catch (error) {
716
1269
  console.error('[useChat] Error fetching config:', error);
@@ -725,8 +1278,13 @@ function useChat(options) {
725
1278
  };
726
1279
  initialize();
727
1280
  return () => {
728
- console.log('[useChat] Effect cleanup, unmounting component');
729
1281
  isMounted = false;
1282
+ // Cleanup resume callbacks
1283
+ state.messages.forEach(message => {
1284
+ if (message.action?.toolCallId) {
1285
+ unregisterActionResumeCallback(message.action.toolCallId);
1286
+ }
1287
+ });
730
1288
  };
731
1289
  }, [widgetId, apiUrl, onError]);
732
1290
  // Save conversation when messages change
@@ -739,9 +1297,6 @@ function useChat(options) {
739
1297
  saveConversation(widgetId, state.conversationId, state.messages);
740
1298
  }
741
1299
  }, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
742
- /**
743
- * Send a message
744
- */
745
1300
  const sendMessage = useCallback(async (content, files) => {
746
1301
  const trimmedContent = content.trim();
747
1302
  const hasFiles = !!files && files.length > 0;
@@ -750,7 +1305,7 @@ function useChat(options) {
750
1305
  const userMessage = {
751
1306
  id: generateMessageId(),
752
1307
  message: {
753
- type: 'human',
1308
+ role: "user",
754
1309
  content: trimmedContent,
755
1310
  },
756
1311
  timestamp: new Date().toISOString(),
@@ -771,7 +1326,7 @@ function useChat(options) {
771
1326
  const conversation = await apiClient.current.getOrCreateConversation();
772
1327
  conversationId = conversation.id;
773
1328
  setState(prev => {
774
- const serverMessages = conversation.messages ?? [];
1329
+ const serverMessages = hydrateMessages(conversation.messages ?? []);
775
1330
  if (serverMessages.length === 0) {
776
1331
  return {
777
1332
  ...prev,
@@ -805,48 +1360,20 @@ function useChat(options) {
805
1360
  }
806
1361
  }
807
1362
  }
808
- // Determine if widget has actions (use agent endpoint)
809
- const useAgent = state.config?.behavior.agentic || (state.config?.actions && state.config.actions.length > 0);
810
1363
  // Stream the response
811
1364
  let lastStreamedMessage = null;
812
- const stream = useAgent
813
- ? apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds)
814
- : apiClient.current.sendMessageStream(conversationId, trimmedContent, fileIds);
815
- for await (const message of stream) {
816
- lastStreamedMessage = message;
817
- // Update state with streamed message
818
- setState(prev => {
819
- const existingIndex = prev.messages.findIndex(m => m.id === message.id);
820
- if (existingIndex >= 0) {
821
- // Update existing streaming message
822
- const newMessages = [...prev.messages];
823
- newMessages[existingIndex] = message;
824
- // Show typing indicator if:
825
- // 1. Message is streaming AND has no content (waiting for first token or after tool call)
826
- // 2. Message is a tool execution (shows loading spinner on the tool)
827
- const isAIMessage = message.message.type === 'ai';
828
- const hasContent = isAIMessage && message.message.content.trim().length > 0;
829
- const isToolExecuting = message.toolExecuting !== undefined;
830
- return {
831
- ...prev,
832
- messages: newMessages,
833
- isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
834
- isLoading: false,
835
- };
836
- }
837
- else {
838
- // Add new streaming message
839
- const isAIMessage = message.message.type === 'ai';
840
- const hasContent = isAIMessage && message.message.content.trim().length > 0;
841
- const isToolExecuting = message.toolExecuting !== undefined;
842
- return {
843
- ...prev,
844
- messages: [...prev.messages, message],
845
- isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
846
- isLoading: false,
847
- };
848
- }
849
- });
1365
+ const streamState = createStreamState();
1366
+ const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds);
1367
+ for await (const event of stream) {
1368
+ if (event.type === "action_request") {
1369
+ await handleActionLoop(apiClient.current, event, streamState, (message) => {
1370
+ lastStreamedMessage = message;
1371
+ }, setState, widgetId, conversationId, () => stateRef.current.messages);
1372
+ break;
1373
+ }
1374
+ handleStreamEvent(event, streamState, (message) => {
1375
+ lastStreamedMessage = message;
1376
+ }, setState);
850
1377
  }
851
1378
  // Stream completed - finalize state
852
1379
  setState(prev => ({
@@ -867,7 +1394,7 @@ function useChat(options) {
867
1394
  const fallbackAssistantMessage = {
868
1395
  id: generateMessageId(),
869
1396
  message: {
870
- type: 'ai',
1397
+ role: "assistant",
871
1398
  content: fallbackMessage,
872
1399
  },
873
1400
  timestamp: new Date().toISOString(),
@@ -886,7 +1413,7 @@ function useChat(options) {
886
1413
  const errorAssistantMessage = {
887
1414
  id: generateMessageId(),
888
1415
  message: {
889
- type: 'ai',
1416
+ role: "assistant",
890
1417
  content: `⚠️ ${errorInfo.message}`,
891
1418
  },
892
1419
  timestamp: new Date().toISOString(),
@@ -924,8 +1451,13 @@ function useChat(options) {
924
1451
  */
925
1452
  const submitFeedback = useCallback(async (messageId, feedback) => {
926
1453
  try {
1454
+ const message = state.messages.find(msg => msg.id === messageId);
1455
+ const messageContent = typeof message?.message.content === "string" ? message.message.content : undefined;
1456
+ const meta = message
1457
+ ? { role: message.message.role, content: messageContent, timestamp: message.timestamp }
1458
+ : undefined;
927
1459
  console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
928
- await apiClient.current.submitFeedback(state.conversationId, messageId, feedback);
1460
+ await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
929
1461
  // Update message with feedback
930
1462
  setState(prev => ({
931
1463
  ...prev,
@@ -959,9 +1491,6 @@ function useChat(options) {
959
1491
  startedAt: entry.lastUpdated,
960
1492
  })));
961
1493
  }, [widgetId, state.config?.settings.persistConversation]);
962
- /**
963
- * Switch to a different conversation (from localStorage first, then fetch from server if needed)
964
- */
965
1494
  const switchConversation = useCallback(async (conversationId) => {
966
1495
  const persistConversation = state.config?.settings.persistConversation ?? true;
967
1496
  // First try to load from localStorage
@@ -971,25 +1500,33 @@ function useChat(options) {
971
1500
  setState(prev => ({
972
1501
  ...prev,
973
1502
  conversationId: stored.conversationId,
974
- messages: stored.messages,
1503
+ messages: hydrateMessages(stored.messages),
975
1504
  }));
976
1505
  setActiveConversation(widgetId, conversationId);
977
1506
  return;
978
1507
  }
979
1508
  }
980
- // If not in localStorage, fetch from server
981
1509
  setState(prev => ({ ...prev, isLoading: true, error: null }));
982
1510
  try {
983
1511
  const conversation = await apiClient.current.getOrCreateConversation(conversationId);
1512
+ const hydratedMessages = hydrateMessages(conversation.messages);
1513
+ // Clear old resume callbacks
1514
+ state.messages.forEach(message => {
1515
+ if (message.action?.toolCallId) {
1516
+ unregisterActionResumeCallback(message.action.toolCallId);
1517
+ }
1518
+ });
984
1519
  setState(prev => ({
985
1520
  ...prev,
986
1521
  conversationId: conversation.id,
987
- messages: conversation.messages,
1522
+ messages: hydratedMessages,
988
1523
  isLoading: false,
989
1524
  }));
1525
+ // Setup new resume callbacks
1526
+ setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
990
1527
  // Save to local storage
991
1528
  if (persistConversation && isStorageAvailable()) {
992
- saveConversation(widgetId, conversation.id, conversation.messages);
1529
+ saveConversation(widgetId, conversation.id, hydratedMessages);
993
1530
  }
994
1531
  }
995
1532
  catch (error) {
@@ -997,9 +1534,6 @@ function useChat(options) {
997
1534
  setState(prev => ({ ...prev, isLoading: false, error: errorInfo.message }));
998
1535
  }
999
1536
  }, [widgetId, state.config?.settings.persistConversation]);
1000
- /**
1001
- * Start a new conversation (keeps history)
1002
- */
1003
1537
  const startNewConversation = useCallback(() => {
1004
1538
  setState(prev => ({
1005
1539
  ...prev,
@@ -1007,15 +1541,11 @@ function useChat(options) {
1007
1541
  conversationId: '',
1008
1542
  error: null,
1009
1543
  }));
1010
- // Clear active conversation but keep history
1011
1544
  const persistConversation = state.config?.settings.persistConversation ?? true;
1012
1545
  if (persistConversation && isStorageAvailable()) {
1013
1546
  clearConversation(widgetId);
1014
1547
  }
1015
1548
  }, [widgetId, state.config?.settings.persistConversation]);
1016
- /**
1017
- * Delete a conversation from history
1018
- */
1019
1549
  const deleteConversation$1 = useCallback((conversationId) => {
1020
1550
  const persistConversation = state.config?.settings.persistConversation ?? true;
1021
1551
  if (!persistConversation || !isStorageAvailable()) {
@@ -27869,12 +28399,12 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27869
28399
  hour12: true,
27870
28400
  });
27871
28401
  };
27872
- const msgType = message.message.type;
28402
+ const role = message.message.role;
27873
28403
  const isError = message.isError || false;
27874
- const isTool = msgType === 'tool';
27875
- const isAssistant = msgType === 'ai';
27876
- const isSystem = msgType === 'system';
27877
- const isHuman = msgType === 'human';
28404
+ const isTool = role === "tool";
28405
+ const isAssistant = role === "assistant";
28406
+ const isSystem = role === "system";
28407
+ const isHuman = role === "user";
27878
28408
  // Tool messages are now handled by ToolMessageGroup in MessageList
27879
28409
  if (isTool) {
27880
28410
  return null;
@@ -27885,7 +28415,10 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27885
28415
  const hasContent = aiContent.trim().length > 0;
27886
28416
  if (!hasContent)
27887
28417
  return null;
27888
- return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxs("div", { className: "ai-chat-error-indicator", children: [jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "error-text", children: "Error" })] })), jsx(Markdown, { remarkPlugins: [remarkGfm], children: aiContent })] }), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] })), showSources && message.sources?.length > 0 && (jsx(Sources, { sources: message.sources, displayMode: sourceDisplayMode }))] }));
28418
+ const actionRenderer = message.action
28419
+ ? getActionRenderer(message.action.implementation)
28420
+ : undefined;
28421
+ return (jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxs("div", { className: "ai-chat-error-indicator", children: [jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsx("span", { className: "error-text", children: "Error" })] })), jsx(Markdown, { remarkPlugins: [remarkGfm], children: aiContent })] }), actionRenderer && message.action && actionRenderer(message), showTimestamp && (jsxs("div", { className: "ai-chat-message-meta", children: [jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] })), showSources && message.sources?.length > 0 && (jsx(Sources, { sources: message.sources, displayMode: sourceDisplayMode }))] }));
27889
28422
  }
27890
28423
  // System message rendering
27891
28424
  if (isSystem) {
@@ -27893,7 +28426,7 @@ const Message = ({ message, showTimestamp = true, enableFeedback = true, showSou
27893
28426
  }
27894
28427
  // Human message rendering
27895
28428
  if (isHuman) {
27896
- const userContent = message.message.content.split('--- File Content ---')[0];
28429
+ const userContent = (message.message.content || '').split('--- File Content ---')[0];
27897
28430
  return (jsxs("div", { className: "ai-chat-message user", children: [jsx("div", { className: "ai-chat-message-content", children: userContent }), showTimestamp && (jsx("div", { className: "ai-chat-message-meta", children: jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }) }))] }));
27898
28431
  }
27899
28432
  return null;
@@ -27910,13 +28443,31 @@ const GearIcon = ({ spinning = false }) => (jsxs("svg", { className: `ai-chat-to
27910
28443
  const CheckIcon = () => (jsx("svg", { className: "ai-chat-tool-check", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "20 6 9 17 4 12" }) }));
27911
28444
  const ErrorIcon = () => (jsx("svg", { className: "ai-chat-tool-error", width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }));
27912
28445
  const ToolMessageGroup = ({ messages }) => {
27913
- const isAnyLoading = messages.some(m => m.isStreaming);
27914
- return (jsx("div", { className: "ai-chat-message tool", children: jsxs("div", { className: "ai-chat-tool-row", children: [jsx(GearIcon, { spinning: isAnyLoading }), jsx("div", { className: "ai-chat-tool-badges", children: messages.map((message) => {
27915
- const toolName = message.toolExecuting || message.message.name || 'Tool';
27916
- const hasError = message.isError || false;
27917
- const isLoading = message.isStreaming;
27918
- return (jsxs("div", { className: `ai-chat-tool-badge ${isLoading ? 'loading' : hasError ? 'error' : 'completed'}`, children: [!isLoading && (hasError ? jsx(ErrorIcon, {}) : jsx(CheckIcon, {})), jsx("span", { className: "tool-name", children: formatToolName(toolName) })] }, message.id));
27919
- }) })] }) }));
28446
+ // Check if any message is loading (for actions, check done flag; otherwise check isStreaming)
28447
+ const isAnyLoading = messages.some(m => {
28448
+ if (m.action) {
28449
+ return !(m.action.done ?? false);
28450
+ }
28451
+ return m.isStreaming;
28452
+ });
28453
+ const actionMessages = messages.filter(message => message.action);
28454
+ return (jsxs("div", { className: "ai-chat-message tool", children: [jsxs("div", { className: "ai-chat-tool-row", children: [jsx(GearIcon, { spinning: isAnyLoading }), jsx("div", { className: "ai-chat-tool-badges", children: messages.map((message) => {
28455
+ const toolName = message.toolExecuting || message.message.name || 'Tool';
28456
+ const hasError = message.isError || false;
28457
+ // For actions, check if done flag is set; otherwise fall back to isStreaming
28458
+ const isDone = message.action ? (message.action.done ?? false) : !message.isStreaming;
28459
+ const isLoading = !isDone;
28460
+ return (jsxs("div", { className: `ai-chat-tool-badge ${isLoading ? 'loading' : hasError ? 'error' : 'completed'}`, children: [!isLoading && (hasError ? jsx(ErrorIcon, {}) : jsx(CheckIcon, {})), jsx("span", { className: "tool-name", children: formatToolName(toolName) })] }, message.id));
28461
+ }) })] }), actionMessages.map((message) => {
28462
+ if (!message.action) {
28463
+ return null;
28464
+ }
28465
+ const renderer = getActionRenderer(message.action.implementation);
28466
+ if (!renderer) {
28467
+ return null;
28468
+ }
28469
+ return (jsx("div", { className: "ai-chat-tool-action", children: renderer(message) }, `action-${message.id}`));
28470
+ })] }));
27920
28471
  };
27921
28472
 
27922
28473
  const TypingIndicator = () => {
@@ -27941,6 +28492,14 @@ const SuggestedQuestions = ({ questions, onQuestionClick, }) => {
27941
28492
  const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', welcomeTitle, welcomeMessage, suggestedQuestions, onSuggestedQuestionClick, onFeedback, }) => {
27942
28493
  const containerRef = useRef(null);
27943
28494
  const messagesEndRef = useRef(null);
28495
+ // Check if there's an active action awaiting user input
28496
+ const hasActiveAction = useMemo(() => {
28497
+ return messages.some(msg => msg.action &&
28498
+ msg.action.state &&
28499
+ msg.action.state.status !== 'completed' &&
28500
+ msg.action.state.status !== 'booked' &&
28501
+ msg.action.state.status !== 'failed');
28502
+ }, [messages]);
27944
28503
  // Auto-scroll to bottom only on initial mount/load
27945
28504
  useEffect(() => {
27946
28505
  const container = containerRef.current;
@@ -27969,16 +28528,16 @@ const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, s
27969
28528
  }
27970
28529
  };
27971
28530
  for (const message of messages) {
27972
- if (message.message.type === 'tool') {
28531
+ if (message.message.role === "tool") {
27973
28532
  // Add to current tool group
27974
28533
  currentToolGroup.push(message);
27975
28534
  }
27976
- else if (message.message.type === 'human') {
28535
+ else if (message.message.role === "user") {
27977
28536
  // Human message breaks tool grouping
27978
28537
  flushToolGroup();
27979
28538
  result.push({ type: 'message', message });
27980
28539
  }
27981
- else if (message.message.type === 'ai') {
28540
+ else if (message.message.role === "assistant") {
27982
28541
  // Skip empty AI messages
27983
28542
  const content = (message.message.content || '').trim();
27984
28543
  if (!content) {
@@ -28004,7 +28563,7 @@ const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, s
28004
28563
  return (jsx(ToolMessageGroup, { messages: item.messages }, `tool-group-${index}`));
28005
28564
  }
28006
28565
  return (jsx(Message, { message: item.message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, showSources: showSources, sourceDisplayMode: sourceDisplayMode, onFeedback: onFeedback }, item.message.id));
28007
- }), isTyping && showTypingIndicator && jsx(TypingIndicator, {}), jsx("div", { ref: messagesEndRef })] }));
28566
+ }), isTyping && showTypingIndicator && !hasActiveAction && jsx(TypingIndicator, {}), jsx("div", { ref: messagesEndRef })] }));
28008
28567
  };
28009
28568
 
28010
28569
  // Allowed file types
@@ -28094,7 +28653,6 @@ const ChatWindow = ({ messages, isLoading, isTyping, error, config, onSendMessag
28094
28653
  conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
28095
28654
  // Override props for live preview
28096
28655
  headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
28097
- console.log('[ChatWindow] Rendering ChatWindow component');
28098
28656
  const appearance = config?.appearance;
28099
28657
  const settings = config?.settings;
28100
28658
  // Check if chat history should be shown (requires both persistConversation AND showChatHistory)
@@ -28105,13 +28663,6 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
28105
28663
  const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
28106
28664
  const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
28107
28665
  const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
28108
- console.log('[ChatWindow] Appearance values:', {
28109
- size,
28110
- headerTitle,
28111
- welcomeTitle,
28112
- welcomeMessage,
28113
- inputPlaceholder,
28114
- });
28115
28666
  // Track if history panel is open
28116
28667
  const [showHistory, setShowHistory] = useState(false);
28117
28668
  // History exit animation when starting a new chat from overview
@@ -28156,7 +28707,7 @@ headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOv
28156
28707
  };
28157
28708
  // Check if message limit is reached
28158
28709
  const maxMessages = settings?.maxMessagesPerSession;
28159
- const userMessageCount = messages.filter(m => m.message.type === 'human').length;
28710
+ const userMessageCount = messages.filter(m => m.message.role === "user").length;
28160
28711
  const isLimitReached = maxMessages ? userMessageCount >= maxMessages : false;
28161
28712
  const handleQuestionClick = (question) => {
28162
28713
  onSendMessage(question);
@@ -28566,34 +29117,7 @@ function createThemeObserver(element, callback) {
28566
29117
  return observer;
28567
29118
  }
28568
29119
 
28569
- function styleInject(css, ref) {
28570
- if ( ref === void 0 ) ref = {};
28571
- var insertAt = ref.insertAt;
28572
-
28573
- if (typeof document === 'undefined') { return; }
28574
-
28575
- var head = document.head || document.getElementsByTagName('head')[0];
28576
- var style = document.createElement('style');
28577
- style.type = 'text/css';
28578
-
28579
- if (insertAt === 'top') {
28580
- if (head.firstChild) {
28581
- head.insertBefore(style, head.firstChild);
28582
- } else {
28583
- head.appendChild(style);
28584
- }
28585
- } else {
28586
- head.appendChild(style);
28587
- }
28588
-
28589
- if (style.styleSheet) {
28590
- style.styleSheet.cssText = css;
28591
- } else {
28592
- style.appendChild(document.createTextNode(css));
28593
- }
28594
- }
28595
-
28596
- 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}";
29120
+ 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}";
28597
29121
  styleInject(css_248z);
28598
29122
 
28599
29123
  // Icon components mapping
@@ -28697,16 +29221,6 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
28697
29221
  mediaQuery.removeEventListener('change', handleMediaChange);
28698
29222
  };
28699
29223
  }, [config]);
28700
- // Debug logging
28701
- useEffect(() => {
28702
- console.log('[ChatWidget] Config loaded:', config ? 'YES' : 'NO');
28703
- if (config) {
28704
- console.log('[ChatWidget] Config details:', {
28705
- accentColor: config.appearance?.primaryColor,
28706
- autoDetectedTheme,
28707
- });
28708
- }
28709
- }, [config, autoDetectedTheme]);
28710
29224
  // Handle auto-open
28711
29225
  useEffect(() => {
28712
29226
  if (config?.settings.autoOpen) {
@@ -28761,17 +29275,8 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
28761
29275
  ...customStyles,
28762
29276
  ...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
28763
29277
  };
28764
- // Debug logging for theme and styles
28765
- useEffect(() => {
28766
- console.log('[ChatWidget] Theme info:', {
28767
- effectiveTheme,
28768
- autoDetectedTheme,
28769
- accentColor,
28770
- });
28771
- }, [effectiveTheme, autoDetectedTheme, accentColor]);
28772
29278
  const handleToggle = () => {
28773
29279
  const newState = !isOpen;
28774
- console.log('[ChatWidget] handleToggle called, setting isOpen to:', newState);
28775
29280
  setIsOpen(newState);
28776
29281
  if (newState) {
28777
29282
  onOpen?.();
@@ -28786,10 +29291,8 @@ const ChatWidget = ({ widgetId, apiUrl = window.location.origin, previewMode = f
28786
29291
  // Don't render until config is loaded to avoid flash of unstyled content
28787
29292
  // In preview mode, config is always available
28788
29293
  if (!config && !previewMode) {
28789
- console.log('[ChatWidget] Not rendering - config not loaded yet');
28790
29294
  return null;
28791
29295
  }
28792
- console.log('[ChatWidget] Rendering widget', { isOpen, hasConfig: !!config });
28793
29296
  // Get button icon based on state
28794
29297
  const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
28795
29298
  return (jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition}`, children: [isOpen && (jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback,