@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.
- package/dist/actions/google-calendar-appointment/component.d.ts +6 -0
- package/dist/actions/google-calendar-appointment/component.d.ts.map +1 -0
- package/dist/actions/google-calendar-appointment/handler.d.ts +2 -0
- package/dist/actions/google-calendar-appointment/handler.d.ts.map +1 -0
- package/dist/actions/google-calendar-appointment/index.d.ts +3 -0
- package/dist/actions/google-calendar-appointment/index.d.ts.map +1 -0
- package/dist/actions/index.d.ts +3 -0
- package/dist/actions/index.d.ts.map +1 -0
- package/dist/actions/registry.d.ts +24 -0
- package/dist/actions/registry.d.ts.map +1 -0
- package/dist/ai-chat-widget.umd.js +803 -300
- package/dist/ai-chat-widget.umd.js.map +1 -1
- package/dist/api/client.d.ts +8 -20
- package/dist/api/client.d.ts.map +1 -1
- package/dist/components/ChatWidget.d.ts.map +1 -1
- package/dist/components/ChatWindow.d.ts.map +1 -1
- package/dist/components/Message.d.ts.map +1 -1
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/ToolMessageGroup.d.ts.map +1 -1
- package/dist/hooks/useChat.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +803 -300
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +803 -300
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +86 -40
- package/dist/types/index.d.ts.map +1 -1
- package/dist/umd.d.ts +2 -1
- package/dist/umd.d.ts.map +1 -1
- package/dist/utils/sse-parser.d.ts +2 -0
- package/dist/utils/sse-parser.d.ts.map +1 -0
- package/dist/utils/storage.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -17341,6 +17341,53 @@
|
|
|
17341
17341
|
|
|
17342
17342
|
var jsxRuntimeExports = requireJsxRuntime();
|
|
17343
17343
|
|
|
17344
|
+
async function* parseSSEStream(response, validator) {
|
|
17345
|
+
if (!response.body) {
|
|
17346
|
+
throw new Error("Response body is null");
|
|
17347
|
+
}
|
|
17348
|
+
const reader = response.body.getReader();
|
|
17349
|
+
const decoder = new TextDecoder();
|
|
17350
|
+
let buffer = "";
|
|
17351
|
+
try {
|
|
17352
|
+
while (true) {
|
|
17353
|
+
const { done, value } = await reader.read();
|
|
17354
|
+
if (done)
|
|
17355
|
+
break;
|
|
17356
|
+
buffer += decoder.decode(value, { stream: true });
|
|
17357
|
+
const chunks = buffer.split("\n\n");
|
|
17358
|
+
buffer = chunks.pop() || "";
|
|
17359
|
+
for (const chunk of chunks) {
|
|
17360
|
+
const lines = chunk.split("\n");
|
|
17361
|
+
for (const line of lines) {
|
|
17362
|
+
if (line.startsWith("data: ")) {
|
|
17363
|
+
try {
|
|
17364
|
+
const data = JSON.parse(line.slice(6));
|
|
17365
|
+
if (validator) {
|
|
17366
|
+
if (validator(data)) {
|
|
17367
|
+
yield data;
|
|
17368
|
+
}
|
|
17369
|
+
else {
|
|
17370
|
+
console.warn("[SSE Parser] Data failed validation:", data);
|
|
17371
|
+
}
|
|
17372
|
+
}
|
|
17373
|
+
else {
|
|
17374
|
+
yield data;
|
|
17375
|
+
}
|
|
17376
|
+
}
|
|
17377
|
+
catch (e) {
|
|
17378
|
+
console.error("[SSE Parser] Failed to parse SSE data:", line, e);
|
|
17379
|
+
throw e;
|
|
17380
|
+
}
|
|
17381
|
+
}
|
|
17382
|
+
}
|
|
17383
|
+
}
|
|
17384
|
+
}
|
|
17385
|
+
}
|
|
17386
|
+
finally {
|
|
17387
|
+
reader.releaseLock();
|
|
17388
|
+
}
|
|
17389
|
+
}
|
|
17390
|
+
|
|
17344
17391
|
/**
|
|
17345
17392
|
* API Client for Widget Communication
|
|
17346
17393
|
* Handles all HTTP requests to the widget API
|
|
@@ -17476,12 +17523,8 @@
|
|
|
17476
17523
|
const result = await response.json();
|
|
17477
17524
|
return result.file;
|
|
17478
17525
|
}
|
|
17479
|
-
|
|
17480
|
-
|
|
17481
|
-
* Returns ConversationMessage[] array
|
|
17482
|
-
*/
|
|
17483
|
-
async sendMessage(conversationId, message, fileIds) {
|
|
17484
|
-
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/chat`, {
|
|
17526
|
+
async *sendAgentMessageStream(conversationId, message, fileIds) {
|
|
17527
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
|
|
17485
17528
|
method: 'POST',
|
|
17486
17529
|
headers: {
|
|
17487
17530
|
'Content-Type': 'application/json',
|
|
@@ -17494,167 +17537,36 @@
|
|
|
17494
17537
|
}),
|
|
17495
17538
|
});
|
|
17496
17539
|
if (!response.ok) {
|
|
17497
|
-
throw await buildApiError(response, 'Failed to send message');
|
|
17498
|
-
}
|
|
17499
|
-
return response.json();
|
|
17500
|
-
}
|
|
17501
|
-
/**
|
|
17502
|
-
* Send a message to agent (with actions support)
|
|
17503
|
-
*/
|
|
17504
|
-
async sendAgentMessage(conversationId, message, fileIds) {
|
|
17505
|
-
try {
|
|
17506
|
-
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
|
|
17507
|
-
method: 'POST',
|
|
17508
|
-
headers: {
|
|
17509
|
-
'Content-Type': 'application/json',
|
|
17510
|
-
},
|
|
17511
|
-
body: JSON.stringify({
|
|
17512
|
-
conversationId: conversationId,
|
|
17513
|
-
message,
|
|
17514
|
-
fileIds,
|
|
17515
|
-
timeZone: this.getTimeZone(),
|
|
17516
|
-
}),
|
|
17517
|
-
});
|
|
17518
|
-
if (!response.ok) {
|
|
17519
|
-
throw await buildApiError(response, `Agent request failed with status ${response.status}`);
|
|
17520
|
-
}
|
|
17521
|
-
const data = await response.json();
|
|
17522
|
-
// Check if response indicates an error
|
|
17523
|
-
if (data.type === 'error') {
|
|
17524
|
-
throw new Error(data.message || 'Agent encountered an error');
|
|
17525
|
-
}
|
|
17526
|
-
return data;
|
|
17527
|
-
}
|
|
17528
|
-
catch (error) {
|
|
17529
|
-
// Enhance error messages
|
|
17530
|
-
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
17531
|
-
throw new ApiError('Network error: Unable to reach the server', 0);
|
|
17532
|
-
}
|
|
17533
|
-
throw error;
|
|
17540
|
+
throw await buildApiError(response, 'Failed to send agent message');
|
|
17534
17541
|
}
|
|
17535
|
-
|
|
17536
|
-
|
|
17537
|
-
* Stream chat message responses
|
|
17538
|
-
*/
|
|
17539
|
-
async *sendMessageStream(conversationId, message, fileIds) {
|
|
17540
|
-
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/chat`, {
|
|
17541
|
-
method: 'POST',
|
|
17542
|
-
headers: {
|
|
17543
|
-
'Content-Type': 'application/json',
|
|
17544
|
-
},
|
|
17545
|
-
body: JSON.stringify({
|
|
17546
|
-
conversationId: conversationId,
|
|
17547
|
-
message,
|
|
17548
|
-
fileIds,
|
|
17549
|
-
timeZone: this.getTimeZone(),
|
|
17550
|
-
}),
|
|
17542
|
+
yield* parseSSEStream(response, (data) => {
|
|
17543
|
+
return typeof data === 'object' && data !== null && 'type' in data;
|
|
17551
17544
|
});
|
|
17552
|
-
if (!response.ok) {
|
|
17553
|
-
throw await buildApiError(response, 'Failed to send message');
|
|
17554
|
-
}
|
|
17555
|
-
if (!response.body) {
|
|
17556
|
-
throw new Error('Response body is null');
|
|
17557
|
-
}
|
|
17558
|
-
const reader = response.body.getReader();
|
|
17559
|
-
const decoder = new TextDecoder();
|
|
17560
|
-
let buffer = '';
|
|
17561
|
-
try {
|
|
17562
|
-
while (true) {
|
|
17563
|
-
const { done, value } = await reader.read();
|
|
17564
|
-
if (done)
|
|
17565
|
-
break;
|
|
17566
|
-
buffer += decoder.decode(value, { stream: true });
|
|
17567
|
-
const lines = buffer.split('\n');
|
|
17568
|
-
buffer = lines.pop() || '';
|
|
17569
|
-
for (const line of lines) {
|
|
17570
|
-
if (line.startsWith('data: ')) {
|
|
17571
|
-
try {
|
|
17572
|
-
const data = JSON.parse(line.slice(6));
|
|
17573
|
-
// Handle error events
|
|
17574
|
-
if (data.type === 'error') {
|
|
17575
|
-
throw new Error(data.error || 'Stream error');
|
|
17576
|
-
}
|
|
17577
|
-
// Yield ConversationMessage objects
|
|
17578
|
-
if (data.id) {
|
|
17579
|
-
yield data;
|
|
17580
|
-
}
|
|
17581
|
-
}
|
|
17582
|
-
catch (e) {
|
|
17583
|
-
console.error('[Widget API Client] Failed to parse SSE data:', line, e);
|
|
17584
|
-
throw e;
|
|
17585
|
-
}
|
|
17586
|
-
}
|
|
17587
|
-
}
|
|
17588
|
-
}
|
|
17589
|
-
}
|
|
17590
|
-
finally {
|
|
17591
|
-
reader.releaseLock();
|
|
17592
|
-
}
|
|
17593
17545
|
}
|
|
17594
|
-
|
|
17595
|
-
|
|
17596
|
-
* Handles streaming events from backend and yields ConversationMessage updates
|
|
17597
|
-
*/
|
|
17598
|
-
async *sendAgentMessageStream(conversationId, message, fileIds) {
|
|
17599
|
-
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
|
|
17546
|
+
async *continueAgentMessageStream(conversationId, toolCallId, state) {
|
|
17547
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
|
|
17600
17548
|
method: 'POST',
|
|
17601
17549
|
headers: {
|
|
17602
17550
|
'Content-Type': 'application/json',
|
|
17603
17551
|
},
|
|
17604
17552
|
body: JSON.stringify({
|
|
17605
17553
|
conversationId: conversationId,
|
|
17606
|
-
|
|
17607
|
-
|
|
17554
|
+
toolCallId,
|
|
17555
|
+
state,
|
|
17608
17556
|
timeZone: this.getTimeZone(),
|
|
17609
17557
|
}),
|
|
17610
17558
|
});
|
|
17611
17559
|
if (!response.ok) {
|
|
17612
|
-
throw await buildApiError(response, 'Failed to
|
|
17613
|
-
}
|
|
17614
|
-
if (!response.body) {
|
|
17615
|
-
throw new Error('Response body is null');
|
|
17616
|
-
}
|
|
17617
|
-
const reader = response.body.getReader();
|
|
17618
|
-
const decoder = new TextDecoder();
|
|
17619
|
-
let buffer = '';
|
|
17620
|
-
try {
|
|
17621
|
-
while (true) {
|
|
17622
|
-
const { done, value } = await reader.read();
|
|
17623
|
-
if (done)
|
|
17624
|
-
break;
|
|
17625
|
-
buffer += decoder.decode(value, { stream: true });
|
|
17626
|
-
const lines = buffer.split('\n');
|
|
17627
|
-
buffer = lines.pop() || '';
|
|
17628
|
-
for (const line of lines) {
|
|
17629
|
-
if (line.startsWith('data: ')) {
|
|
17630
|
-
try {
|
|
17631
|
-
const data = JSON.parse(line.slice(6));
|
|
17632
|
-
// Handle error events
|
|
17633
|
-
if (data.type === 'error') {
|
|
17634
|
-
throw new Error(data.error || 'Stream error');
|
|
17635
|
-
}
|
|
17636
|
-
// Yield ConversationMessage objects that come from the backend
|
|
17637
|
-
// The backend yields full ConversationMessage objects during streaming
|
|
17638
|
-
if (data.id) {
|
|
17639
|
-
yield data;
|
|
17640
|
-
}
|
|
17641
|
-
}
|
|
17642
|
-
catch (e) {
|
|
17643
|
-
console.error('[Widget API Client] Failed to parse SSE data:', line, e);
|
|
17644
|
-
throw e;
|
|
17645
|
-
}
|
|
17646
|
-
}
|
|
17647
|
-
}
|
|
17648
|
-
}
|
|
17649
|
-
}
|
|
17650
|
-
finally {
|
|
17651
|
-
reader.releaseLock();
|
|
17560
|
+
throw await buildApiError(response, 'Failed to continue agent');
|
|
17652
17561
|
}
|
|
17562
|
+
yield* parseSSEStream(response, (data) => {
|
|
17563
|
+
return typeof data === 'object' && data !== null && 'type' in data;
|
|
17564
|
+
});
|
|
17653
17565
|
}
|
|
17654
17566
|
/**
|
|
17655
17567
|
* Submit feedback for a message
|
|
17656
17568
|
*/
|
|
17657
|
-
async submitFeedback(sessionId, messageId, feedback) {
|
|
17569
|
+
async submitFeedback(sessionId, messageId, feedback, meta) {
|
|
17658
17570
|
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/feedback`, {
|
|
17659
17571
|
method: 'POST',
|
|
17660
17572
|
headers: {
|
|
@@ -17664,6 +17576,9 @@
|
|
|
17664
17576
|
conversationId: sessionId,
|
|
17665
17577
|
messageId: messageId,
|
|
17666
17578
|
feedback,
|
|
17579
|
+
messageRole: meta?.role,
|
|
17580
|
+
messageContent: meta?.content,
|
|
17581
|
+
messageTimestamp: meta?.timestamp,
|
|
17667
17582
|
}),
|
|
17668
17583
|
});
|
|
17669
17584
|
if (!response.ok) {
|
|
@@ -17714,6 +17629,173 @@
|
|
|
17714
17629
|
return `msg_${timestamp}_${randomStr}`;
|
|
17715
17630
|
}
|
|
17716
17631
|
|
|
17632
|
+
const pendingResolvers = new Map();
|
|
17633
|
+
const resumeCallbacks = new Map();
|
|
17634
|
+
const frontendActionHandlers = {};
|
|
17635
|
+
const actionRenderers = {};
|
|
17636
|
+
function getFrontendActionHandler(implementation) {
|
|
17637
|
+
return frontendActionHandlers[implementation];
|
|
17638
|
+
}
|
|
17639
|
+
function getActionRenderer(implementation) {
|
|
17640
|
+
return actionRenderers[implementation];
|
|
17641
|
+
}
|
|
17642
|
+
function getActionPrompt(implementation) {
|
|
17643
|
+
if (implementation === "google-calendar-appointment") {
|
|
17644
|
+
return "Select a date to continue.";
|
|
17645
|
+
}
|
|
17646
|
+
return "Action input required.";
|
|
17647
|
+
}
|
|
17648
|
+
function waitForActionState(toolCallId) {
|
|
17649
|
+
return new Promise((resolve) => {
|
|
17650
|
+
pendingResolvers.set(toolCallId, resolve);
|
|
17651
|
+
});
|
|
17652
|
+
}
|
|
17653
|
+
function resolveActionState(toolCallId, state) {
|
|
17654
|
+
const resolver = pendingResolvers.get(toolCallId);
|
|
17655
|
+
if (resolver) {
|
|
17656
|
+
pendingResolvers.delete(toolCallId);
|
|
17657
|
+
resolver(state);
|
|
17658
|
+
return;
|
|
17659
|
+
}
|
|
17660
|
+
// If no active resolver, check for a resume callback (for page reload scenario)
|
|
17661
|
+
const resumeCallback = resumeCallbacks.get(toolCallId);
|
|
17662
|
+
if (resumeCallback) {
|
|
17663
|
+
resumeCallback(state).catch((error) => {
|
|
17664
|
+
console.error("[Action] Failed to resume action:", error);
|
|
17665
|
+
});
|
|
17666
|
+
}
|
|
17667
|
+
}
|
|
17668
|
+
function registerActionResumeCallback(toolCallId, callback) {
|
|
17669
|
+
resumeCallbacks.set(toolCallId, callback);
|
|
17670
|
+
}
|
|
17671
|
+
function unregisterActionResumeCallback(toolCallId) {
|
|
17672
|
+
resumeCallbacks.delete(toolCallId);
|
|
17673
|
+
}
|
|
17674
|
+
|
|
17675
|
+
function groupSlotsByDate(slots) {
|
|
17676
|
+
const grouped = new Map();
|
|
17677
|
+
for (const slot of slots) {
|
|
17678
|
+
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
17679
|
+
continue;
|
|
17680
|
+
}
|
|
17681
|
+
const date = slot.startTime.slice(0, 10);
|
|
17682
|
+
if (!grouped.has(date)) {
|
|
17683
|
+
grouped.set(date, []);
|
|
17684
|
+
}
|
|
17685
|
+
grouped.get(date).push(slot);
|
|
17686
|
+
}
|
|
17687
|
+
return grouped;
|
|
17688
|
+
}
|
|
17689
|
+
function formatDate(dateStr) {
|
|
17690
|
+
try {
|
|
17691
|
+
const date = new Date(dateStr);
|
|
17692
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
17693
|
+
weekday: "short",
|
|
17694
|
+
month: "short",
|
|
17695
|
+
day: "numeric",
|
|
17696
|
+
}).format(date);
|
|
17697
|
+
}
|
|
17698
|
+
catch {
|
|
17699
|
+
return dateStr;
|
|
17700
|
+
}
|
|
17701
|
+
}
|
|
17702
|
+
function GoogleCalendarAppointmentCard({ message }) {
|
|
17703
|
+
const action = message.action;
|
|
17704
|
+
if (!action || action.implementation !== "google-calendar-appointment") {
|
|
17705
|
+
return null;
|
|
17706
|
+
}
|
|
17707
|
+
const rawSlots = action.state.availableSlots;
|
|
17708
|
+
const availableSlots = Array.isArray(rawSlots)
|
|
17709
|
+
? rawSlots.filter((slot) => slot !== null &&
|
|
17710
|
+
slot !== undefined &&
|
|
17711
|
+
typeof slot === "object" &&
|
|
17712
|
+
"startTime" in slot &&
|
|
17713
|
+
"endTime" in slot &&
|
|
17714
|
+
typeof slot.startTime === "string" &&
|
|
17715
|
+
typeof slot.endTime === "string")
|
|
17716
|
+
: [];
|
|
17717
|
+
const allowTopic = action.state.allowTopic !== false;
|
|
17718
|
+
const isBooked = action.state.status === "booked";
|
|
17719
|
+
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
17720
|
+
const dates = Array.from(slotsByDate.keys()).sort();
|
|
17721
|
+
const [selectedDate, setSelectedDate] = reactExports.useState(dates[0] ?? "");
|
|
17722
|
+
const [selectedSlot, setSelectedSlot] = reactExports.useState(null);
|
|
17723
|
+
const [topic, setTopic] = reactExports.useState("");
|
|
17724
|
+
const [error, setError] = reactExports.useState(null);
|
|
17725
|
+
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
17726
|
+
const onConfirm = () => {
|
|
17727
|
+
if (!selectedSlot) {
|
|
17728
|
+
setError("Please select a time slot.");
|
|
17729
|
+
return;
|
|
17730
|
+
}
|
|
17731
|
+
if (allowTopic && !topic.trim()) {
|
|
17732
|
+
setError("Please enter a topic for the meeting.");
|
|
17733
|
+
return;
|
|
17734
|
+
}
|
|
17735
|
+
setError(null);
|
|
17736
|
+
resolveActionState(action.toolCallId, {
|
|
17737
|
+
...action.state,
|
|
17738
|
+
selectedSlot: {
|
|
17739
|
+
startTime: selectedSlot.startTime,
|
|
17740
|
+
endTime: selectedSlot.endTime,
|
|
17741
|
+
},
|
|
17742
|
+
topic: allowTopic ? topic.trim() : null,
|
|
17743
|
+
});
|
|
17744
|
+
};
|
|
17745
|
+
if (isBooked) {
|
|
17746
|
+
const rawBookedSlot = action.state.selectedSlot;
|
|
17747
|
+
const bookedSlot = rawBookedSlot &&
|
|
17748
|
+
typeof rawBookedSlot === "object" &&
|
|
17749
|
+
"startTime" in rawBookedSlot &&
|
|
17750
|
+
"endTime" in rawBookedSlot
|
|
17751
|
+
? rawBookedSlot
|
|
17752
|
+
: null;
|
|
17753
|
+
const bookedTopic = typeof action.state.topic === "string" ? action.state.topic : null;
|
|
17754
|
+
const eventLink = typeof action.state.bookedEventLink === "string" ? action.state.bookedEventLink : null;
|
|
17755
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-card ai-chat-action-booked", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon-success", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.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"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [bookedTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label", children: "Topic:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value", children: bookedTopic })] })), bookedSlot && bookedSlot.startTime && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-detail", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-action-label", children: "Time:" }), jsxRuntimeExports.jsx("span", { className: "ai-chat-action-value", children: bookedSlot.displayTime || new Date(bookedSlot.startTime).toLocaleString() })] })), eventLink && (jsxRuntimeExports.jsx("a", { href: eventLink, target: "_blank", rel: "noopener noreferrer", className: "ai-chat-action-link", children: "View in Google Calendar \u2192" }))] })] }));
|
|
17756
|
+
}
|
|
17757
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-card", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-header", children: [jsxRuntimeExports.jsx("svg", { className: "ai-chat-action-icon", viewBox: "0 0 20 20", fill: "currentColor", children: jsxRuntimeExports.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"] }), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-body", children: [allowTopic && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { htmlFor: `topic-${action.toolCallId}`, className: "ai-chat-action-label", children: "Meeting Topic" }), jsxRuntimeExports.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) })] })), jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Date" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-date-grid", children: dates.slice(0, 7).map((date) => (jsxRuntimeExports.jsx("button", { type: "button", className: `ai-chat-action-date-btn ${selectedDate === date ? "active" : ""}`, onClick: () => {
|
|
17758
|
+
setSelectedDate(date);
|
|
17759
|
+
setSelectedSlot(null);
|
|
17760
|
+
}, children: formatDate(date) }, date))) })] }), selectedDate && slotsForSelectedDate.length > 0 && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-action-field", children: [jsxRuntimeExports.jsx("label", { className: "ai-chat-action-label", children: "Select Time" }), jsxRuntimeExports.jsx("div", { className: "ai-chat-action-time-grid", children: slotsForSelectedDate.map((slot) => (jsxRuntimeExports.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 && jsxRuntimeExports.jsx("div", { className: "ai-chat-action-error", children: error }), jsxRuntimeExports.jsx("button", { className: "ai-chat-action-button", type: "button", onClick: onConfirm, disabled: !selectedSlot, children: "Confirm Appointment" }), availableSlots.length === 0 && (jsxRuntimeExports.jsx("div", { className: "ai-chat-action-hint", children: "No available time slots found." }))] })] }));
|
|
17761
|
+
}
|
|
17762
|
+
|
|
17763
|
+
frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
|
|
17764
|
+
return waitForActionState(context.toolCallId);
|
|
17765
|
+
};
|
|
17766
|
+
|
|
17767
|
+
function styleInject(css, ref) {
|
|
17768
|
+
if ( ref === void 0 ) ref = {};
|
|
17769
|
+
var insertAt = ref.insertAt;
|
|
17770
|
+
|
|
17771
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
17772
|
+
|
|
17773
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
17774
|
+
var style = document.createElement('style');
|
|
17775
|
+
style.type = 'text/css';
|
|
17776
|
+
|
|
17777
|
+
if (insertAt === 'top') {
|
|
17778
|
+
if (head.firstChild) {
|
|
17779
|
+
head.insertBefore(style, head.firstChild);
|
|
17780
|
+
} else {
|
|
17781
|
+
head.appendChild(style);
|
|
17782
|
+
}
|
|
17783
|
+
} else {
|
|
17784
|
+
head.appendChild(style);
|
|
17785
|
+
}
|
|
17786
|
+
|
|
17787
|
+
if (style.styleSheet) {
|
|
17788
|
+
style.styleSheet.cssText = css;
|
|
17789
|
+
} else {
|
|
17790
|
+
style.appendChild(document.createTextNode(css));
|
|
17791
|
+
}
|
|
17792
|
+
}
|
|
17793
|
+
|
|
17794
|
+
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)}";
|
|
17795
|
+
styleInject(css_248z$1);
|
|
17796
|
+
|
|
17797
|
+
actionRenderers["google-calendar-appointment"] = (message) => (jsxRuntimeExports.jsx(GoogleCalendarAppointmentCard, { message: message }));
|
|
17798
|
+
|
|
17717
17799
|
/**
|
|
17718
17800
|
* Local Storage Utilities
|
|
17719
17801
|
* Handles conversation persistence in browser localStorage
|
|
@@ -17775,9 +17857,12 @@
|
|
|
17775
17857
|
* Get preview text from messages
|
|
17776
17858
|
*/
|
|
17777
17859
|
function getConversationPreview(messages) {
|
|
17778
|
-
const firstUserMessage = messages.find(m => m.message.
|
|
17860
|
+
const firstUserMessage = messages.find(m => m.message.role === "user");
|
|
17779
17861
|
if (firstUserMessage) {
|
|
17780
|
-
|
|
17862
|
+
const content = typeof firstUserMessage.message.content === "string"
|
|
17863
|
+
? firstUserMessage.message.content
|
|
17864
|
+
: "";
|
|
17865
|
+
return content.slice(0, 100);
|
|
17781
17866
|
}
|
|
17782
17867
|
return 'New conversation';
|
|
17783
17868
|
}
|
|
@@ -17932,6 +18017,473 @@
|
|
|
17932
18017
|
* useChat Hook
|
|
17933
18018
|
* Main state management for chat functionality
|
|
17934
18019
|
*/
|
|
18020
|
+
function hydrateToolNames(messages) {
|
|
18021
|
+
const toolCallNameById = new Map();
|
|
18022
|
+
for (const entry of messages) {
|
|
18023
|
+
if (entry.message.role !== "assistant") {
|
|
18024
|
+
continue;
|
|
18025
|
+
}
|
|
18026
|
+
const toolCalls = entry.message.tool_calls;
|
|
18027
|
+
if (!Array.isArray(toolCalls)) {
|
|
18028
|
+
continue;
|
|
18029
|
+
}
|
|
18030
|
+
for (const call of toolCalls) {
|
|
18031
|
+
const callId = call?.id;
|
|
18032
|
+
const callName = call?.function?.name;
|
|
18033
|
+
if (callId && callName) {
|
|
18034
|
+
toolCallNameById.set(callId, callName);
|
|
18035
|
+
}
|
|
18036
|
+
}
|
|
18037
|
+
}
|
|
18038
|
+
if (toolCallNameById.size === 0) {
|
|
18039
|
+
return messages;
|
|
18040
|
+
}
|
|
18041
|
+
return messages.map((entry) => {
|
|
18042
|
+
if (entry.message.role !== "tool") {
|
|
18043
|
+
return entry;
|
|
18044
|
+
}
|
|
18045
|
+
const toolCallId = entry.message.tool_call_id;
|
|
18046
|
+
const resolvedName = toolCallNameById.get(toolCallId);
|
|
18047
|
+
if (!resolvedName) {
|
|
18048
|
+
return entry;
|
|
18049
|
+
}
|
|
18050
|
+
const currentName = entry.message.name;
|
|
18051
|
+
const nextName = currentName && currentName.trim().length > 0 ? currentName : resolvedName;
|
|
18052
|
+
const nextToolExecuting = entry.toolExecuting || resolvedName;
|
|
18053
|
+
if (nextName === currentName && nextToolExecuting === entry.toolExecuting) {
|
|
18054
|
+
return entry;
|
|
18055
|
+
}
|
|
18056
|
+
return {
|
|
18057
|
+
...entry,
|
|
18058
|
+
message: { ...entry.message, name: nextName },
|
|
18059
|
+
toolExecuting: nextToolExecuting,
|
|
18060
|
+
};
|
|
18061
|
+
});
|
|
18062
|
+
}
|
|
18063
|
+
function hydrateActionContent(messages) {
|
|
18064
|
+
return messages.map((entry) => {
|
|
18065
|
+
if (entry.message.role !== "assistant" || !entry.action) {
|
|
18066
|
+
return entry;
|
|
18067
|
+
}
|
|
18068
|
+
const content = typeof entry.message.content === "string" ? entry.message.content : "";
|
|
18069
|
+
if (content.trim().length > 0) {
|
|
18070
|
+
return entry;
|
|
18071
|
+
}
|
|
18072
|
+
return {
|
|
18073
|
+
...entry,
|
|
18074
|
+
message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
|
|
18075
|
+
};
|
|
18076
|
+
});
|
|
18077
|
+
}
|
|
18078
|
+
function hydrateMessages(messages) {
|
|
18079
|
+
return hydrateActionContent(hydrateToolNames(messages));
|
|
18080
|
+
}
|
|
18081
|
+
function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
|
|
18082
|
+
// Find all incomplete actions and register resume callbacks
|
|
18083
|
+
for (const message of messages) {
|
|
18084
|
+
if (message.action && !message.action.done) {
|
|
18085
|
+
const toolCallId = message.action.toolCallId;
|
|
18086
|
+
const toolName = message.message.name || message.toolExecuting || "tool";
|
|
18087
|
+
registerActionResumeCallback(toolCallId, async (newState) => {
|
|
18088
|
+
// When user interacts with the action after reload, continue the stream
|
|
18089
|
+
try {
|
|
18090
|
+
// Update the action message with the new state
|
|
18091
|
+
setState(prev => ({
|
|
18092
|
+
...prev,
|
|
18093
|
+
messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
|
|
18094
|
+
? {
|
|
18095
|
+
...m,
|
|
18096
|
+
action: m.action ? { ...m.action, state: newState } : undefined,
|
|
18097
|
+
}
|
|
18098
|
+
: m),
|
|
18099
|
+
isTyping: true,
|
|
18100
|
+
}));
|
|
18101
|
+
const streamState = createStreamState();
|
|
18102
|
+
// Continue the agent stream with the new state
|
|
18103
|
+
for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
|
|
18104
|
+
if (event.type === "done") {
|
|
18105
|
+
finalizeToolMessage(streamState, setState, toolCallId, toolName);
|
|
18106
|
+
streamState.sources = event.sources;
|
|
18107
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
18108
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
|
|
18109
|
+
continue;
|
|
18110
|
+
}
|
|
18111
|
+
if (event.type === "error") {
|
|
18112
|
+
const errorMessage = {
|
|
18113
|
+
id: generateMessageId(),
|
|
18114
|
+
message: {
|
|
18115
|
+
role: "assistant",
|
|
18116
|
+
content: `Error: ${event.error}`,
|
|
18117
|
+
},
|
|
18118
|
+
timestamp: new Date().toISOString(),
|
|
18119
|
+
sources: [],
|
|
18120
|
+
isError: true,
|
|
18121
|
+
};
|
|
18122
|
+
upsertMessage(setState, errorMessage, false);
|
|
18123
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
18124
|
+
return;
|
|
18125
|
+
}
|
|
18126
|
+
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
18127
|
+
}
|
|
18128
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
18129
|
+
}
|
|
18130
|
+
catch (error) {
|
|
18131
|
+
console.error("[Action Resume] Failed to continue stream:", error);
|
|
18132
|
+
setState(prev => ({ ...prev, isTyping: false, error: error instanceof Error ? error.message : "Failed to resume action" }));
|
|
18133
|
+
throw error;
|
|
18134
|
+
}
|
|
18135
|
+
});
|
|
18136
|
+
}
|
|
18137
|
+
}
|
|
18138
|
+
}
|
|
18139
|
+
function createStreamState() {
|
|
18140
|
+
return {
|
|
18141
|
+
currentContent: "",
|
|
18142
|
+
currentMessageId: generateMessageId(),
|
|
18143
|
+
activeToolCallCount: 0,
|
|
18144
|
+
newMessageIds: new Set(),
|
|
18145
|
+
sources: [],
|
|
18146
|
+
toolCallToActionId: {},
|
|
18147
|
+
};
|
|
18148
|
+
}
|
|
18149
|
+
function upsertMessage(setState, message, isTyping) {
|
|
18150
|
+
setState(prev => {
|
|
18151
|
+
const existingIndex = prev.messages.findIndex(m => m.id === message.id);
|
|
18152
|
+
if (existingIndex >= 0) {
|
|
18153
|
+
const newMessages = [...prev.messages];
|
|
18154
|
+
newMessages[existingIndex] = message;
|
|
18155
|
+
return { ...prev, messages: newMessages, isTyping, isLoading: false };
|
|
18156
|
+
}
|
|
18157
|
+
return {
|
|
18158
|
+
...prev,
|
|
18159
|
+
messages: [...prev.messages, message],
|
|
18160
|
+
isTyping,
|
|
18161
|
+
isLoading: false,
|
|
18162
|
+
};
|
|
18163
|
+
});
|
|
18164
|
+
}
|
|
18165
|
+
function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionId) {
|
|
18166
|
+
setState(prev => ({
|
|
18167
|
+
...prev,
|
|
18168
|
+
messages: prev.messages.map(msg => (messageIds.has(msg.id)
|
|
18169
|
+
? { ...msg, sources, toolCallToActionId }
|
|
18170
|
+
: msg)),
|
|
18171
|
+
isTyping: false,
|
|
18172
|
+
}));
|
|
18173
|
+
}
|
|
18174
|
+
function handleContentEvent(event, streamState, onMessageUpdate, setState) {
|
|
18175
|
+
streamState.currentContent += event.content;
|
|
18176
|
+
const assistantMessage = {
|
|
18177
|
+
id: streamState.currentMessageId,
|
|
18178
|
+
message: { role: "assistant", content: streamState.currentContent },
|
|
18179
|
+
timestamp: new Date().toISOString(),
|
|
18180
|
+
sources: streamState.sources,
|
|
18181
|
+
isStreaming: true,
|
|
18182
|
+
};
|
|
18183
|
+
streamState.newMessageIds.add(assistantMessage.id);
|
|
18184
|
+
onMessageUpdate(assistantMessage);
|
|
18185
|
+
const hasContent = assistantMessage.message.content?.trim().length || 0 > 0;
|
|
18186
|
+
const isToolExecuting = streamState.activeToolCallCount > 0;
|
|
18187
|
+
const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
|
|
18188
|
+
upsertMessage(setState, assistantMessage, isTyping);
|
|
18189
|
+
}
|
|
18190
|
+
function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
|
|
18191
|
+
if (streamState.currentContent.trim()) {
|
|
18192
|
+
const finalAssistant = {
|
|
18193
|
+
id: streamState.currentMessageId,
|
|
18194
|
+
message: { role: "assistant", content: streamState.currentContent },
|
|
18195
|
+
timestamp: new Date().toISOString(),
|
|
18196
|
+
sources: streamState.sources,
|
|
18197
|
+
isStreaming: false,
|
|
18198
|
+
};
|
|
18199
|
+
streamState.newMessageIds.add(finalAssistant.id);
|
|
18200
|
+
onMessageUpdate(finalAssistant);
|
|
18201
|
+
upsertMessage(setState, finalAssistant, true);
|
|
18202
|
+
streamState.currentContent = "";
|
|
18203
|
+
streamState.currentMessageId = generateMessageId();
|
|
18204
|
+
}
|
|
18205
|
+
const toolMessageId = event.tool_call_id;
|
|
18206
|
+
streamState.activeToolCallCount += 1;
|
|
18207
|
+
streamState.newMessageIds.add(toolMessageId);
|
|
18208
|
+
const toolMessage = {
|
|
18209
|
+
id: toolMessageId,
|
|
18210
|
+
sources: [],
|
|
18211
|
+
message: { role: "tool", content: "", tool_call_id: event.tool_call_id, name: event.tool_name },
|
|
18212
|
+
timestamp: new Date().toISOString(),
|
|
18213
|
+
isStreaming: true,
|
|
18214
|
+
toolExecuting: event.tool_name,
|
|
18215
|
+
};
|
|
18216
|
+
upsertMessage(setState, toolMessage, true);
|
|
18217
|
+
}
|
|
18218
|
+
function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
18219
|
+
// Update state and mark action as done in a single setState call
|
|
18220
|
+
setState(prev => {
|
|
18221
|
+
const messages = prev.messages.map((msg) => {
|
|
18222
|
+
const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
|
|
18223
|
+
if (!matchesToolCall) {
|
|
18224
|
+
return msg;
|
|
18225
|
+
}
|
|
18226
|
+
const existingName = msg.message.name || event.tool_name;
|
|
18227
|
+
return {
|
|
18228
|
+
...msg,
|
|
18229
|
+
message: {
|
|
18230
|
+
role: "tool",
|
|
18231
|
+
content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
|
|
18232
|
+
tool_call_id: event.tool_call_id,
|
|
18233
|
+
name: existingName,
|
|
18234
|
+
},
|
|
18235
|
+
isStreaming: false,
|
|
18236
|
+
toolExecuting: existingName,
|
|
18237
|
+
action: msg.action ? {
|
|
18238
|
+
...msg.action,
|
|
18239
|
+
state: event.state || msg.action.state,
|
|
18240
|
+
done: true, // Mark action as completed
|
|
18241
|
+
} : undefined,
|
|
18242
|
+
};
|
|
18243
|
+
});
|
|
18244
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
18245
|
+
});
|
|
18246
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
18247
|
+
}
|
|
18248
|
+
function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
|
|
18249
|
+
setState(prev => {
|
|
18250
|
+
const messages = prev.messages.map((entry) => {
|
|
18251
|
+
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === event.tool_call_id;
|
|
18252
|
+
if (!matchesToolCall) {
|
|
18253
|
+
return entry;
|
|
18254
|
+
}
|
|
18255
|
+
const name = entry.message.name || "tool";
|
|
18256
|
+
const toolMessage = {
|
|
18257
|
+
...entry,
|
|
18258
|
+
message: {
|
|
18259
|
+
role: "tool",
|
|
18260
|
+
content: event.error || "Tool execution failed",
|
|
18261
|
+
tool_call_id: event.tool_call_id,
|
|
18262
|
+
name,
|
|
18263
|
+
},
|
|
18264
|
+
timestamp: new Date().toISOString(),
|
|
18265
|
+
isStreaming: false,
|
|
18266
|
+
isError: true,
|
|
18267
|
+
toolExecuting: name,
|
|
18268
|
+
};
|
|
18269
|
+
return toolMessage;
|
|
18270
|
+
});
|
|
18271
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
18272
|
+
});
|
|
18273
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
18274
|
+
}
|
|
18275
|
+
function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
|
|
18276
|
+
setState(prev => {
|
|
18277
|
+
const messages = prev.messages.map((entry) => {
|
|
18278
|
+
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
|
|
18279
|
+
if (!matchesToolCall) {
|
|
18280
|
+
return entry;
|
|
18281
|
+
}
|
|
18282
|
+
const existingName = entry.message.name || toolName;
|
|
18283
|
+
return {
|
|
18284
|
+
...entry,
|
|
18285
|
+
message: {
|
|
18286
|
+
role: "tool",
|
|
18287
|
+
content: typeof entry.message.content === "string" ? entry.message.content : "",
|
|
18288
|
+
tool_call_id: toolCallId,
|
|
18289
|
+
name: existingName,
|
|
18290
|
+
},
|
|
18291
|
+
isStreaming: false,
|
|
18292
|
+
toolExecuting: existingName,
|
|
18293
|
+
action: entry.action ? {
|
|
18294
|
+
...entry.action,
|
|
18295
|
+
done: true, // Mark action as completed
|
|
18296
|
+
} : undefined,
|
|
18297
|
+
};
|
|
18298
|
+
});
|
|
18299
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
18300
|
+
});
|
|
18301
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
18302
|
+
}
|
|
18303
|
+
function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
|
|
18304
|
+
streamState.sources = event.sources;
|
|
18305
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
18306
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
|
|
18307
|
+
}
|
|
18308
|
+
function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
|
|
18309
|
+
const toolNames = event.tool_calls.map(call => call.name).join(", ");
|
|
18310
|
+
const notice = toolNames
|
|
18311
|
+
? `Awaiting external tool results: ${toolNames}.`
|
|
18312
|
+
: "Awaiting external tool results.";
|
|
18313
|
+
const haltMessage = {
|
|
18314
|
+
id: generateMessageId(),
|
|
18315
|
+
message: { role: "assistant", content: notice },
|
|
18316
|
+
timestamp: new Date().toISOString(),
|
|
18317
|
+
sources: [],
|
|
18318
|
+
isError: true,
|
|
18319
|
+
};
|
|
18320
|
+
onMessageUpdate(haltMessage);
|
|
18321
|
+
upsertMessage(setState, haltMessage, false);
|
|
18322
|
+
setState(prev => ({ ...prev, error: "Awaiting external tool handling." }));
|
|
18323
|
+
}
|
|
18324
|
+
function handleErrorEvent(event, _streamState, onMessageUpdate, setState) {
|
|
18325
|
+
const errorMessage = {
|
|
18326
|
+
id: generateMessageId(),
|
|
18327
|
+
message: { role: "assistant", content: `⚠️ ${event.error}` },
|
|
18328
|
+
timestamp: new Date().toISOString(),
|
|
18329
|
+
sources: [],
|
|
18330
|
+
isError: true,
|
|
18331
|
+
};
|
|
18332
|
+
onMessageUpdate(errorMessage);
|
|
18333
|
+
upsertMessage(setState, errorMessage, false);
|
|
18334
|
+
setState(prev => ({ ...prev, error: event.error }));
|
|
18335
|
+
}
|
|
18336
|
+
const eventHandlers = {
|
|
18337
|
+
content: handleContentEvent,
|
|
18338
|
+
tool_start: handleToolStartEvent,
|
|
18339
|
+
tool_end: handleToolEndEvent,
|
|
18340
|
+
tool_error: handleToolErrorEvent,
|
|
18341
|
+
done: handleDoneEvent,
|
|
18342
|
+
halt: handleHaltEvent,
|
|
18343
|
+
error: handleErrorEvent,
|
|
18344
|
+
action_request: () => { },
|
|
18345
|
+
};
|
|
18346
|
+
function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
|
|
18347
|
+
if (event.type === "tool_start" || event.type === "tool_end" || event.type === "tool_error" || event.type === "action_request" || event.type === "done" || event.type === "halt") {
|
|
18348
|
+
console.log("[Widget] stream event:", {
|
|
18349
|
+
type: event.type,
|
|
18350
|
+
toolCallId: "tool_call_id" in event ? event.tool_call_id : undefined,
|
|
18351
|
+
toolName: "tool_name" in event ? event.tool_name : undefined,
|
|
18352
|
+
});
|
|
18353
|
+
}
|
|
18354
|
+
const handler = eventHandlers[event.type];
|
|
18355
|
+
if (handler) {
|
|
18356
|
+
handler(event, streamState, onMessageUpdate, setState);
|
|
18357
|
+
}
|
|
18358
|
+
else {
|
|
18359
|
+
console.warn('[Chat] Unknown event type:', event.type);
|
|
18360
|
+
}
|
|
18361
|
+
}
|
|
18362
|
+
async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
|
|
18363
|
+
let pendingEvent = initialEvent;
|
|
18364
|
+
while (pendingEvent) {
|
|
18365
|
+
streamState.toolCallToActionId = pendingEvent.tool_call_to_action_id;
|
|
18366
|
+
const resumeToolCallId = pendingEvent.tool_call_id;
|
|
18367
|
+
const existingToolMessage = getMessages().find((entry) => entry.message.role === "tool" && entry.message.tool_call_id === resumeToolCallId);
|
|
18368
|
+
const toolMessageId = existingToolMessage?.id ?? resumeToolCallId;
|
|
18369
|
+
const toolName = existingToolMessage?.message.name ?? "tool";
|
|
18370
|
+
const toolMessage = {
|
|
18371
|
+
id: toolMessageId,
|
|
18372
|
+
sources: [],
|
|
18373
|
+
message: {
|
|
18374
|
+
role: "tool",
|
|
18375
|
+
content: "",
|
|
18376
|
+
tool_call_id: resumeToolCallId,
|
|
18377
|
+
name: toolName,
|
|
18378
|
+
},
|
|
18379
|
+
timestamp: new Date().toISOString(),
|
|
18380
|
+
isStreaming: true,
|
|
18381
|
+
toolExecuting: toolName,
|
|
18382
|
+
action: {
|
|
18383
|
+
implementation: pendingEvent.implementation,
|
|
18384
|
+
toolCallId: pendingEvent.tool_call_id,
|
|
18385
|
+
actionId: pendingEvent.action_id,
|
|
18386
|
+
input: pendingEvent.input,
|
|
18387
|
+
state: pendingEvent.state,
|
|
18388
|
+
done: false, // Action not yet completed
|
|
18389
|
+
},
|
|
18390
|
+
};
|
|
18391
|
+
if (streamState.activeToolCallCount === 0) {
|
|
18392
|
+
streamState.activeToolCallCount = 1;
|
|
18393
|
+
}
|
|
18394
|
+
onMessageUpdate(toolMessage);
|
|
18395
|
+
upsertMessage(setState, toolMessage, true);
|
|
18396
|
+
const handler = getFrontendActionHandler(pendingEvent.implementation);
|
|
18397
|
+
if (!handler) {
|
|
18398
|
+
const errorMessage = {
|
|
18399
|
+
id: generateMessageId(),
|
|
18400
|
+
message: {
|
|
18401
|
+
role: "assistant",
|
|
18402
|
+
content: `⚠️ No frontend handler for action '${pendingEvent.implementation}'.`,
|
|
18403
|
+
},
|
|
18404
|
+
timestamp: new Date().toISOString(),
|
|
18405
|
+
sources: [],
|
|
18406
|
+
isError: true,
|
|
18407
|
+
};
|
|
18408
|
+
onMessageUpdate(errorMessage);
|
|
18409
|
+
upsertMessage(setState, errorMessage, false);
|
|
18410
|
+
setState(prev => ({ ...prev, error: `Missing frontend handler: ${pendingEvent?.implementation}` }));
|
|
18411
|
+
return;
|
|
18412
|
+
}
|
|
18413
|
+
let nextState;
|
|
18414
|
+
try {
|
|
18415
|
+
nextState = await handler(pendingEvent.input, pendingEvent.state, {
|
|
18416
|
+
widgetId,
|
|
18417
|
+
conversationId,
|
|
18418
|
+
toolCallId: pendingEvent.tool_call_id,
|
|
18419
|
+
actionId: pendingEvent.action_id,
|
|
18420
|
+
implementation: pendingEvent.implementation,
|
|
18421
|
+
});
|
|
18422
|
+
}
|
|
18423
|
+
catch (error) {
|
|
18424
|
+
const errorMessage = error instanceof Error ? error.message : "Frontend action failed.";
|
|
18425
|
+
const errorMessageEntry = {
|
|
18426
|
+
id: generateMessageId(),
|
|
18427
|
+
message: { role: "assistant", content: `⚠️ ${errorMessage}` },
|
|
18428
|
+
timestamp: new Date().toISOString(),
|
|
18429
|
+
sources: [],
|
|
18430
|
+
isError: true,
|
|
18431
|
+
};
|
|
18432
|
+
onMessageUpdate(errorMessageEntry);
|
|
18433
|
+
upsertMessage(setState, errorMessageEntry, false);
|
|
18434
|
+
setState(prev => ({ ...prev, error: errorMessage }));
|
|
18435
|
+
return;
|
|
18436
|
+
}
|
|
18437
|
+
pendingEvent = null;
|
|
18438
|
+
const updatedToolMessage = {
|
|
18439
|
+
...toolMessage,
|
|
18440
|
+
action: toolMessage.action
|
|
18441
|
+
? {
|
|
18442
|
+
...toolMessage.action,
|
|
18443
|
+
state: nextState,
|
|
18444
|
+
}
|
|
18445
|
+
: undefined,
|
|
18446
|
+
};
|
|
18447
|
+
upsertMessage(setState, updatedToolMessage, true);
|
|
18448
|
+
let streamEnded = false;
|
|
18449
|
+
for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
|
|
18450
|
+
if (event.type === "action_request") {
|
|
18451
|
+
pendingEvent = event;
|
|
18452
|
+
break;
|
|
18453
|
+
}
|
|
18454
|
+
if (event.type === "done") {
|
|
18455
|
+
// Don't extract and update state from done event - the state was already
|
|
18456
|
+
// updated by tool_end event or by the user's frontend action.
|
|
18457
|
+
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
18458
|
+
// Handle the done event but skip the tool finalization part since we already did it
|
|
18459
|
+
streamState.sources = event.sources;
|
|
18460
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
18461
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
|
|
18462
|
+
streamEnded = true;
|
|
18463
|
+
continue; // Skip handleStreamEvent for done events to avoid state conflicts
|
|
18464
|
+
}
|
|
18465
|
+
if (event.type === "error") {
|
|
18466
|
+
const errorMessage = {
|
|
18467
|
+
id: generateMessageId(),
|
|
18468
|
+
message: {
|
|
18469
|
+
role: "assistant",
|
|
18470
|
+
content: `Error occurred during action execution: ${event.error}`,
|
|
18471
|
+
},
|
|
18472
|
+
timestamp: new Date().toISOString(),
|
|
18473
|
+
sources: [],
|
|
18474
|
+
isError: true,
|
|
18475
|
+
};
|
|
18476
|
+
upsertMessage(setState, errorMessage, false);
|
|
18477
|
+
return;
|
|
18478
|
+
}
|
|
18479
|
+
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
18480
|
+
}
|
|
18481
|
+
// If stream ended without a done event (e.g., only tool_end was sent), finalize the tool message
|
|
18482
|
+
if (!streamEnded && !pendingEvent) {
|
|
18483
|
+
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
18484
|
+
}
|
|
18485
|
+
}
|
|
18486
|
+
}
|
|
17935
18487
|
function deriveErrorInfo(error) {
|
|
17936
18488
|
if (error instanceof ApiError) {
|
|
17937
18489
|
const retryAfterSeconds = typeof error.retryAfterMs === 'number'
|
|
@@ -18004,6 +18556,10 @@
|
|
|
18004
18556
|
conversationId: '', // Will be set after loading conversation
|
|
18005
18557
|
config: null,
|
|
18006
18558
|
});
|
|
18559
|
+
const stateRef = reactExports.useRef(state);
|
|
18560
|
+
reactExports.useEffect(() => {
|
|
18561
|
+
stateRef.current = state;
|
|
18562
|
+
}, [state]);
|
|
18007
18563
|
// Chat history state
|
|
18008
18564
|
const [conversations, setConversations] = reactExports.useState([]);
|
|
18009
18565
|
const apiClient = reactExports.useRef(new WidgetApiClient({ widgetId, apiUrl }));
|
|
@@ -18011,18 +18567,12 @@
|
|
|
18011
18567
|
reactExports.useEffect(() => {
|
|
18012
18568
|
// Skip initialization in preview mode
|
|
18013
18569
|
if (skipInitialization) {
|
|
18014
|
-
console.log('[useChat] Skipping initialization (preview mode)');
|
|
18015
18570
|
return;
|
|
18016
18571
|
}
|
|
18017
18572
|
let isMounted = true;
|
|
18018
|
-
console.log('[useChat] Effect running, mounting component');
|
|
18019
18573
|
const initialize = async () => {
|
|
18020
18574
|
try {
|
|
18021
|
-
console.log('[useChat] Fetching config...');
|
|
18022
18575
|
const config = await apiClient.current.getConfig();
|
|
18023
|
-
console.log('[useChat] Config fetched successfully:', {
|
|
18024
|
-
hasAppearance: !!config.appearance,
|
|
18025
|
-
});
|
|
18026
18576
|
const persistConversation = config.settings.persistConversation ?? true;
|
|
18027
18577
|
let conversationId = '';
|
|
18028
18578
|
let messages = [];
|
|
@@ -18033,7 +18583,7 @@
|
|
|
18033
18583
|
try {
|
|
18034
18584
|
const conversation = await apiClient.current.getOrCreateConversation(storedId);
|
|
18035
18585
|
conversationId = conversation.id;
|
|
18036
|
-
messages = conversation.messages;
|
|
18586
|
+
messages = hydrateMessages(conversation.messages);
|
|
18037
18587
|
}
|
|
18038
18588
|
catch (conversationError) {
|
|
18039
18589
|
console.warn('Failed to load existing conversation:', conversationError);
|
|
@@ -18041,16 +18591,19 @@
|
|
|
18041
18591
|
}
|
|
18042
18592
|
}
|
|
18043
18593
|
if (!isMounted) {
|
|
18044
|
-
console.log('[useChat] Component unmounted, skipping state update');
|
|
18045
18594
|
return;
|
|
18046
18595
|
}
|
|
18047
|
-
|
|
18596
|
+
const hydratedMessages = hydrateMessages(messages);
|
|
18048
18597
|
setState(prev => ({
|
|
18049
18598
|
...prev,
|
|
18050
18599
|
config,
|
|
18051
18600
|
conversationId,
|
|
18052
|
-
messages,
|
|
18601
|
+
messages: hydratedMessages,
|
|
18053
18602
|
}));
|
|
18603
|
+
// Setup resume callbacks for incomplete actions
|
|
18604
|
+
if (conversationId) {
|
|
18605
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
|
|
18606
|
+
}
|
|
18054
18607
|
}
|
|
18055
18608
|
catch (error) {
|
|
18056
18609
|
console.error('[useChat] Error fetching config:', error);
|
|
@@ -18065,8 +18618,13 @@
|
|
|
18065
18618
|
};
|
|
18066
18619
|
initialize();
|
|
18067
18620
|
return () => {
|
|
18068
|
-
console.log('[useChat] Effect cleanup, unmounting component');
|
|
18069
18621
|
isMounted = false;
|
|
18622
|
+
// Cleanup resume callbacks
|
|
18623
|
+
state.messages.forEach(message => {
|
|
18624
|
+
if (message.action?.toolCallId) {
|
|
18625
|
+
unregisterActionResumeCallback(message.action.toolCallId);
|
|
18626
|
+
}
|
|
18627
|
+
});
|
|
18070
18628
|
};
|
|
18071
18629
|
}, [widgetId, apiUrl, onError]);
|
|
18072
18630
|
// Save conversation when messages change
|
|
@@ -18079,9 +18637,6 @@
|
|
|
18079
18637
|
saveConversation(widgetId, state.conversationId, state.messages);
|
|
18080
18638
|
}
|
|
18081
18639
|
}, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
|
|
18082
|
-
/**
|
|
18083
|
-
* Send a message
|
|
18084
|
-
*/
|
|
18085
18640
|
const sendMessage = reactExports.useCallback(async (content, files) => {
|
|
18086
18641
|
const trimmedContent = content.trim();
|
|
18087
18642
|
const hasFiles = !!files && files.length > 0;
|
|
@@ -18090,7 +18645,7 @@
|
|
|
18090
18645
|
const userMessage = {
|
|
18091
18646
|
id: generateMessageId(),
|
|
18092
18647
|
message: {
|
|
18093
|
-
|
|
18648
|
+
role: "user",
|
|
18094
18649
|
content: trimmedContent,
|
|
18095
18650
|
},
|
|
18096
18651
|
timestamp: new Date().toISOString(),
|
|
@@ -18111,7 +18666,7 @@
|
|
|
18111
18666
|
const conversation = await apiClient.current.getOrCreateConversation();
|
|
18112
18667
|
conversationId = conversation.id;
|
|
18113
18668
|
setState(prev => {
|
|
18114
|
-
const serverMessages = conversation.messages ?? [];
|
|
18669
|
+
const serverMessages = hydrateMessages(conversation.messages ?? []);
|
|
18115
18670
|
if (serverMessages.length === 0) {
|
|
18116
18671
|
return {
|
|
18117
18672
|
...prev,
|
|
@@ -18145,48 +18700,20 @@
|
|
|
18145
18700
|
}
|
|
18146
18701
|
}
|
|
18147
18702
|
}
|
|
18148
|
-
// Determine if widget has actions (use agent endpoint)
|
|
18149
|
-
const useAgent = state.config?.behavior.agentic || (state.config?.actions && state.config.actions.length > 0);
|
|
18150
18703
|
// Stream the response
|
|
18151
18704
|
let lastStreamedMessage = null;
|
|
18152
|
-
const
|
|
18153
|
-
|
|
18154
|
-
|
|
18155
|
-
|
|
18156
|
-
|
|
18157
|
-
|
|
18158
|
-
|
|
18159
|
-
|
|
18160
|
-
|
|
18161
|
-
|
|
18162
|
-
|
|
18163
|
-
|
|
18164
|
-
// Show typing indicator if:
|
|
18165
|
-
// 1. Message is streaming AND has no content (waiting for first token or after tool call)
|
|
18166
|
-
// 2. Message is a tool execution (shows loading spinner on the tool)
|
|
18167
|
-
const isAIMessage = message.message.type === 'ai';
|
|
18168
|
-
const hasContent = isAIMessage && message.message.content.trim().length > 0;
|
|
18169
|
-
const isToolExecuting = message.toolExecuting !== undefined;
|
|
18170
|
-
return {
|
|
18171
|
-
...prev,
|
|
18172
|
-
messages: newMessages,
|
|
18173
|
-
isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
|
|
18174
|
-
isLoading: false,
|
|
18175
|
-
};
|
|
18176
|
-
}
|
|
18177
|
-
else {
|
|
18178
|
-
// Add new streaming message
|
|
18179
|
-
const isAIMessage = message.message.type === 'ai';
|
|
18180
|
-
const hasContent = isAIMessage && message.message.content.trim().length > 0;
|
|
18181
|
-
const isToolExecuting = message.toolExecuting !== undefined;
|
|
18182
|
-
return {
|
|
18183
|
-
...prev,
|
|
18184
|
-
messages: [...prev.messages, message],
|
|
18185
|
-
isTyping: (message.isStreaming && !hasContent && isAIMessage) || isToolExecuting,
|
|
18186
|
-
isLoading: false,
|
|
18187
|
-
};
|
|
18188
|
-
}
|
|
18189
|
-
});
|
|
18705
|
+
const streamState = createStreamState();
|
|
18706
|
+
const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds);
|
|
18707
|
+
for await (const event of stream) {
|
|
18708
|
+
if (event.type === "action_request") {
|
|
18709
|
+
await handleActionLoop(apiClient.current, event, streamState, (message) => {
|
|
18710
|
+
lastStreamedMessage = message;
|
|
18711
|
+
}, setState, widgetId, conversationId, () => stateRef.current.messages);
|
|
18712
|
+
break;
|
|
18713
|
+
}
|
|
18714
|
+
handleStreamEvent(event, streamState, (message) => {
|
|
18715
|
+
lastStreamedMessage = message;
|
|
18716
|
+
}, setState);
|
|
18190
18717
|
}
|
|
18191
18718
|
// Stream completed - finalize state
|
|
18192
18719
|
setState(prev => ({
|
|
@@ -18207,7 +18734,7 @@
|
|
|
18207
18734
|
const fallbackAssistantMessage = {
|
|
18208
18735
|
id: generateMessageId(),
|
|
18209
18736
|
message: {
|
|
18210
|
-
|
|
18737
|
+
role: "assistant",
|
|
18211
18738
|
content: fallbackMessage,
|
|
18212
18739
|
},
|
|
18213
18740
|
timestamp: new Date().toISOString(),
|
|
@@ -18226,7 +18753,7 @@
|
|
|
18226
18753
|
const errorAssistantMessage = {
|
|
18227
18754
|
id: generateMessageId(),
|
|
18228
18755
|
message: {
|
|
18229
|
-
|
|
18756
|
+
role: "assistant",
|
|
18230
18757
|
content: `⚠️ ${errorInfo.message}`,
|
|
18231
18758
|
},
|
|
18232
18759
|
timestamp: new Date().toISOString(),
|
|
@@ -18264,8 +18791,13 @@
|
|
|
18264
18791
|
*/
|
|
18265
18792
|
const submitFeedback = reactExports.useCallback(async (messageId, feedback) => {
|
|
18266
18793
|
try {
|
|
18794
|
+
const message = state.messages.find(msg => msg.id === messageId);
|
|
18795
|
+
const messageContent = typeof message?.message.content === "string" ? message.message.content : undefined;
|
|
18796
|
+
const meta = message
|
|
18797
|
+
? { role: message.message.role, content: messageContent, timestamp: message.timestamp }
|
|
18798
|
+
: undefined;
|
|
18267
18799
|
console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
|
|
18268
|
-
await apiClient.current.submitFeedback(state.conversationId, messageId, feedback);
|
|
18800
|
+
await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
|
|
18269
18801
|
// Update message with feedback
|
|
18270
18802
|
setState(prev => ({
|
|
18271
18803
|
...prev,
|
|
@@ -18299,9 +18831,6 @@
|
|
|
18299
18831
|
startedAt: entry.lastUpdated,
|
|
18300
18832
|
})));
|
|
18301
18833
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
18302
|
-
/**
|
|
18303
|
-
* Switch to a different conversation (from localStorage first, then fetch from server if needed)
|
|
18304
|
-
*/
|
|
18305
18834
|
const switchConversation = reactExports.useCallback(async (conversationId) => {
|
|
18306
18835
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
18307
18836
|
// First try to load from localStorage
|
|
@@ -18311,25 +18840,33 @@
|
|
|
18311
18840
|
setState(prev => ({
|
|
18312
18841
|
...prev,
|
|
18313
18842
|
conversationId: stored.conversationId,
|
|
18314
|
-
messages: stored.messages,
|
|
18843
|
+
messages: hydrateMessages(stored.messages),
|
|
18315
18844
|
}));
|
|
18316
18845
|
setActiveConversation(widgetId, conversationId);
|
|
18317
18846
|
return;
|
|
18318
18847
|
}
|
|
18319
18848
|
}
|
|
18320
|
-
// If not in localStorage, fetch from server
|
|
18321
18849
|
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
18322
18850
|
try {
|
|
18323
18851
|
const conversation = await apiClient.current.getOrCreateConversation(conversationId);
|
|
18852
|
+
const hydratedMessages = hydrateMessages(conversation.messages);
|
|
18853
|
+
// Clear old resume callbacks
|
|
18854
|
+
state.messages.forEach(message => {
|
|
18855
|
+
if (message.action?.toolCallId) {
|
|
18856
|
+
unregisterActionResumeCallback(message.action.toolCallId);
|
|
18857
|
+
}
|
|
18858
|
+
});
|
|
18324
18859
|
setState(prev => ({
|
|
18325
18860
|
...prev,
|
|
18326
18861
|
conversationId: conversation.id,
|
|
18327
|
-
messages:
|
|
18862
|
+
messages: hydratedMessages,
|
|
18328
18863
|
isLoading: false,
|
|
18329
18864
|
}));
|
|
18865
|
+
// Setup new resume callbacks
|
|
18866
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
|
|
18330
18867
|
// Save to local storage
|
|
18331
18868
|
if (persistConversation && isStorageAvailable()) {
|
|
18332
|
-
saveConversation(widgetId, conversation.id,
|
|
18869
|
+
saveConversation(widgetId, conversation.id, hydratedMessages);
|
|
18333
18870
|
}
|
|
18334
18871
|
}
|
|
18335
18872
|
catch (error) {
|
|
@@ -18337,9 +18874,6 @@
|
|
|
18337
18874
|
setState(prev => ({ ...prev, isLoading: false, error: errorInfo.message }));
|
|
18338
18875
|
}
|
|
18339
18876
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
18340
|
-
/**
|
|
18341
|
-
* Start a new conversation (keeps history)
|
|
18342
|
-
*/
|
|
18343
18877
|
const startNewConversation = reactExports.useCallback(() => {
|
|
18344
18878
|
setState(prev => ({
|
|
18345
18879
|
...prev,
|
|
@@ -18347,15 +18881,11 @@
|
|
|
18347
18881
|
conversationId: '',
|
|
18348
18882
|
error: null,
|
|
18349
18883
|
}));
|
|
18350
|
-
// Clear active conversation but keep history
|
|
18351
18884
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
18352
18885
|
if (persistConversation && isStorageAvailable()) {
|
|
18353
18886
|
clearConversation(widgetId);
|
|
18354
18887
|
}
|
|
18355
18888
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
18356
|
-
/**
|
|
18357
|
-
* Delete a conversation from history
|
|
18358
|
-
*/
|
|
18359
18889
|
const deleteConversation$1 = reactExports.useCallback((conversationId) => {
|
|
18360
18890
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
18361
18891
|
if (!persistConversation || !isStorageAvailable()) {
|
|
@@ -45205,12 +45735,12 @@
|
|
|
45205
45735
|
hour12: true,
|
|
45206
45736
|
});
|
|
45207
45737
|
};
|
|
45208
|
-
const
|
|
45738
|
+
const role = message.message.role;
|
|
45209
45739
|
const isError = message.isError || false;
|
|
45210
|
-
const isTool =
|
|
45211
|
-
const isAssistant =
|
|
45212
|
-
const isSystem =
|
|
45213
|
-
const isHuman =
|
|
45740
|
+
const isTool = role === "tool";
|
|
45741
|
+
const isAssistant = role === "assistant";
|
|
45742
|
+
const isSystem = role === "system";
|
|
45743
|
+
const isHuman = role === "user";
|
|
45214
45744
|
// Tool messages are now handled by ToolMessageGroup in MessageList
|
|
45215
45745
|
if (isTool) {
|
|
45216
45746
|
return null;
|
|
@@ -45221,7 +45751,10 @@
|
|
|
45221
45751
|
const hasContent = aiContent.trim().length > 0;
|
|
45222
45752
|
if (!hasContent)
|
|
45223
45753
|
return null;
|
|
45224
|
-
|
|
45754
|
+
const actionRenderer = message.action
|
|
45755
|
+
? getActionRenderer(message.action.implementation)
|
|
45756
|
+
: undefined;
|
|
45757
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-message assistant ${isError ? 'error' : ''}`, children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-message-content", children: [isError && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-error-indicator", children: [jsxRuntimeExports.jsx("span", { className: "error-icon", children: "\u26A0\uFE0F" }), jsxRuntimeExports.jsx("span", { className: "error-text", children: "Error" })] })), jsxRuntimeExports.jsx(Markdown, { remarkPlugins: [remarkGfm], children: aiContent })] }), actionRenderer && message.action && actionRenderer(message), showTimestamp && (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message-meta", children: [jsxRuntimeExports.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }), enableFeedback && onFeedback && (jsxRuntimeExports.jsx(FeedbackButtons, { messageId: message.id, currentFeedback: message.feedback, onFeedback: onFeedback }))] })), showSources && message.sources?.length > 0 && (jsxRuntimeExports.jsx(Sources, { sources: message.sources, displayMode: sourceDisplayMode }))] }));
|
|
45225
45758
|
}
|
|
45226
45759
|
// System message rendering
|
|
45227
45760
|
if (isSystem) {
|
|
@@ -45229,7 +45762,7 @@
|
|
|
45229
45762
|
}
|
|
45230
45763
|
// Human message rendering
|
|
45231
45764
|
if (isHuman) {
|
|
45232
|
-
const userContent = message.message.content.split('--- File Content ---')[0];
|
|
45765
|
+
const userContent = (message.message.content || '').split('--- File Content ---')[0];
|
|
45233
45766
|
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message user", children: [jsxRuntimeExports.jsx("div", { className: "ai-chat-message-content", children: userContent }), showTimestamp && (jsxRuntimeExports.jsx("div", { className: "ai-chat-message-meta", children: jsxRuntimeExports.jsx("span", { className: "ai-chat-message-timestamp", children: formatTime(message.timestamp) }) }))] }));
|
|
45234
45767
|
}
|
|
45235
45768
|
return null;
|
|
@@ -45246,13 +45779,31 @@
|
|
|
45246
45779
|
const CheckIcon = () => (jsxRuntimeExports.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: jsxRuntimeExports.jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
45247
45780
|
const ErrorIcon = () => (jsxRuntimeExports.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: jsxRuntimeExports.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }));
|
|
45248
45781
|
const ToolMessageGroup = ({ messages }) => {
|
|
45249
|
-
|
|
45250
|
-
|
|
45251
|
-
|
|
45252
|
-
|
|
45253
|
-
|
|
45254
|
-
|
|
45255
|
-
|
|
45782
|
+
// Check if any message is loading (for actions, check done flag; otherwise check isStreaming)
|
|
45783
|
+
const isAnyLoading = messages.some(m => {
|
|
45784
|
+
if (m.action) {
|
|
45785
|
+
return !(m.action.done ?? false);
|
|
45786
|
+
}
|
|
45787
|
+
return m.isStreaming;
|
|
45788
|
+
});
|
|
45789
|
+
const actionMessages = messages.filter(message => message.action);
|
|
45790
|
+
return (jsxRuntimeExports.jsxs("div", { className: "ai-chat-message tool", children: [jsxRuntimeExports.jsxs("div", { className: "ai-chat-tool-row", children: [jsxRuntimeExports.jsx(GearIcon, { spinning: isAnyLoading }), jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-badges", children: messages.map((message) => {
|
|
45791
|
+
const toolName = message.toolExecuting || message.message.name || 'Tool';
|
|
45792
|
+
const hasError = message.isError || false;
|
|
45793
|
+
// For actions, check if done flag is set; otherwise fall back to isStreaming
|
|
45794
|
+
const isDone = message.action ? (message.action.done ?? false) : !message.isStreaming;
|
|
45795
|
+
const isLoading = !isDone;
|
|
45796
|
+
return (jsxRuntimeExports.jsxs("div", { className: `ai-chat-tool-badge ${isLoading ? 'loading' : hasError ? 'error' : 'completed'}`, children: [!isLoading && (hasError ? jsxRuntimeExports.jsx(ErrorIcon, {}) : jsxRuntimeExports.jsx(CheckIcon, {})), jsxRuntimeExports.jsx("span", { className: "tool-name", children: formatToolName(toolName) })] }, message.id));
|
|
45797
|
+
}) })] }), actionMessages.map((message) => {
|
|
45798
|
+
if (!message.action) {
|
|
45799
|
+
return null;
|
|
45800
|
+
}
|
|
45801
|
+
const renderer = getActionRenderer(message.action.implementation);
|
|
45802
|
+
if (!renderer) {
|
|
45803
|
+
return null;
|
|
45804
|
+
}
|
|
45805
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-action", children: renderer(message) }, `action-${message.id}`));
|
|
45806
|
+
})] }));
|
|
45256
45807
|
};
|
|
45257
45808
|
|
|
45258
45809
|
const TypingIndicator = () => {
|
|
@@ -45277,6 +45828,14 @@
|
|
|
45277
45828
|
const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', welcomeTitle, welcomeMessage, suggestedQuestions, onSuggestedQuestionClick, onFeedback, }) => {
|
|
45278
45829
|
const containerRef = reactExports.useRef(null);
|
|
45279
45830
|
const messagesEndRef = reactExports.useRef(null);
|
|
45831
|
+
// Check if there's an active action awaiting user input
|
|
45832
|
+
const hasActiveAction = reactExports.useMemo(() => {
|
|
45833
|
+
return messages.some(msg => msg.action &&
|
|
45834
|
+
msg.action.state &&
|
|
45835
|
+
msg.action.state.status !== 'completed' &&
|
|
45836
|
+
msg.action.state.status !== 'booked' &&
|
|
45837
|
+
msg.action.state.status !== 'failed');
|
|
45838
|
+
}, [messages]);
|
|
45280
45839
|
// Auto-scroll to bottom only on initial mount/load
|
|
45281
45840
|
reactExports.useEffect(() => {
|
|
45282
45841
|
const container = containerRef.current;
|
|
@@ -45305,16 +45864,16 @@
|
|
|
45305
45864
|
}
|
|
45306
45865
|
};
|
|
45307
45866
|
for (const message of messages) {
|
|
45308
|
-
if (message.message.
|
|
45867
|
+
if (message.message.role === "tool") {
|
|
45309
45868
|
// Add to current tool group
|
|
45310
45869
|
currentToolGroup.push(message);
|
|
45311
45870
|
}
|
|
45312
|
-
else if (message.message.
|
|
45871
|
+
else if (message.message.role === "user") {
|
|
45313
45872
|
// Human message breaks tool grouping
|
|
45314
45873
|
flushToolGroup();
|
|
45315
45874
|
result.push({ type: 'message', message });
|
|
45316
45875
|
}
|
|
45317
|
-
else if (message.message.
|
|
45876
|
+
else if (message.message.role === "assistant") {
|
|
45318
45877
|
// Skip empty AI messages
|
|
45319
45878
|
const content = (message.message.content || '').trim();
|
|
45320
45879
|
if (!content) {
|
|
@@ -45340,7 +45899,7 @@
|
|
|
45340
45899
|
return (jsxRuntimeExports.jsx(ToolMessageGroup, { messages: item.messages }, `tool-group-${index}`));
|
|
45341
45900
|
}
|
|
45342
45901
|
return (jsxRuntimeExports.jsx(Message, { message: item.message, showTimestamp: showTimestamps, enableFeedback: enableFeedback, showSources: showSources, sourceDisplayMode: sourceDisplayMode, onFeedback: onFeedback }, item.message.id));
|
|
45343
|
-
}), isTyping && showTypingIndicator && jsxRuntimeExports.jsx(TypingIndicator, {}), jsxRuntimeExports.jsx("div", { ref: messagesEndRef })] }));
|
|
45902
|
+
}), isTyping && showTypingIndicator && !hasActiveAction && jsxRuntimeExports.jsx(TypingIndicator, {}), jsxRuntimeExports.jsx("div", { ref: messagesEndRef })] }));
|
|
45344
45903
|
};
|
|
45345
45904
|
|
|
45346
45905
|
// Allowed file types
|
|
@@ -45430,7 +45989,6 @@
|
|
|
45430
45989
|
conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
|
|
45431
45990
|
// Override props for live preview
|
|
45432
45991
|
headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
|
|
45433
|
-
console.log('[ChatWindow] Rendering ChatWindow component');
|
|
45434
45992
|
const appearance = config?.appearance;
|
|
45435
45993
|
const settings = config?.settings;
|
|
45436
45994
|
// Check if chat history should be shown (requires both persistConversation AND showChatHistory)
|
|
@@ -45441,13 +45999,6 @@
|
|
|
45441
45999
|
const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
|
|
45442
46000
|
const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
|
|
45443
46001
|
const inputPlaceholder = placeholderOverride ?? appearance?.placeholder ?? 'Ask me anything...';
|
|
45444
|
-
console.log('[ChatWindow] Appearance values:', {
|
|
45445
|
-
size,
|
|
45446
|
-
headerTitle,
|
|
45447
|
-
welcomeTitle,
|
|
45448
|
-
welcomeMessage,
|
|
45449
|
-
inputPlaceholder,
|
|
45450
|
-
});
|
|
45451
46002
|
// Track if history panel is open
|
|
45452
46003
|
const [showHistory, setShowHistory] = reactExports.useState(false);
|
|
45453
46004
|
// History exit animation when starting a new chat from overview
|
|
@@ -45492,7 +46043,7 @@
|
|
|
45492
46043
|
};
|
|
45493
46044
|
// Check if message limit is reached
|
|
45494
46045
|
const maxMessages = settings?.maxMessagesPerSession;
|
|
45495
|
-
const userMessageCount = messages.filter(m => m.message.
|
|
46046
|
+
const userMessageCount = messages.filter(m => m.message.role === "user").length;
|
|
45496
46047
|
const isLimitReached = maxMessages ? userMessageCount >= maxMessages : false;
|
|
45497
46048
|
const handleQuestionClick = (question) => {
|
|
45498
46049
|
onSendMessage(question);
|
|
@@ -45902,34 +46453,7 @@
|
|
|
45902
46453
|
return observer;
|
|
45903
46454
|
}
|
|
45904
46455
|
|
|
45905
|
-
function styleInject(css, ref) {
|
|
45906
|
-
if ( ref === void 0 ) ref = {};
|
|
45907
|
-
var insertAt = ref.insertAt;
|
|
45908
|
-
|
|
45909
|
-
if (typeof document === 'undefined') { return; }
|
|
45910
|
-
|
|
45911
|
-
var head = document.head || document.getElementsByTagName('head')[0];
|
|
45912
|
-
var style = document.createElement('style');
|
|
45913
|
-
style.type = 'text/css';
|
|
45914
|
-
|
|
45915
|
-
if (insertAt === 'top') {
|
|
45916
|
-
if (head.firstChild) {
|
|
45917
|
-
head.insertBefore(style, head.firstChild);
|
|
45918
|
-
} else {
|
|
45919
|
-
head.appendChild(style);
|
|
45920
|
-
}
|
|
45921
|
-
} else {
|
|
45922
|
-
head.appendChild(style);
|
|
45923
|
-
}
|
|
45924
|
-
|
|
45925
|
-
if (style.styleSheet) {
|
|
45926
|
-
style.styleSheet.cssText = css;
|
|
45927
|
-
} else {
|
|
45928
|
-
style.appendChild(document.createTextNode(css));
|
|
45929
|
-
}
|
|
45930
|
-
}
|
|
45931
|
-
|
|
45932
|
-
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}";
|
|
46456
|
+
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}";
|
|
45933
46457
|
styleInject(css_248z);
|
|
45934
46458
|
|
|
45935
46459
|
// Icon components mapping
|
|
@@ -46033,16 +46557,6 @@
|
|
|
46033
46557
|
mediaQuery.removeEventListener('change', handleMediaChange);
|
|
46034
46558
|
};
|
|
46035
46559
|
}, [config]);
|
|
46036
|
-
// Debug logging
|
|
46037
|
-
reactExports.useEffect(() => {
|
|
46038
|
-
console.log('[ChatWidget] Config loaded:', config ? 'YES' : 'NO');
|
|
46039
|
-
if (config) {
|
|
46040
|
-
console.log('[ChatWidget] Config details:', {
|
|
46041
|
-
accentColor: config.appearance?.primaryColor,
|
|
46042
|
-
autoDetectedTheme,
|
|
46043
|
-
});
|
|
46044
|
-
}
|
|
46045
|
-
}, [config, autoDetectedTheme]);
|
|
46046
46560
|
// Handle auto-open
|
|
46047
46561
|
reactExports.useEffect(() => {
|
|
46048
46562
|
if (config?.settings.autoOpen) {
|
|
@@ -46097,17 +46611,8 @@
|
|
|
46097
46611
|
...customStyles,
|
|
46098
46612
|
...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
|
|
46099
46613
|
};
|
|
46100
|
-
// Debug logging for theme and styles
|
|
46101
|
-
reactExports.useEffect(() => {
|
|
46102
|
-
console.log('[ChatWidget] Theme info:', {
|
|
46103
|
-
effectiveTheme,
|
|
46104
|
-
autoDetectedTheme,
|
|
46105
|
-
accentColor,
|
|
46106
|
-
});
|
|
46107
|
-
}, [effectiveTheme, autoDetectedTheme, accentColor]);
|
|
46108
46614
|
const handleToggle = () => {
|
|
46109
46615
|
const newState = !isOpen;
|
|
46110
|
-
console.log('[ChatWidget] handleToggle called, setting isOpen to:', newState);
|
|
46111
46616
|
setIsOpen(newState);
|
|
46112
46617
|
if (newState) {
|
|
46113
46618
|
onOpen?.();
|
|
@@ -46122,10 +46627,8 @@
|
|
|
46122
46627
|
// Don't render until config is loaded to avoid flash of unstyled content
|
|
46123
46628
|
// In preview mode, config is always available
|
|
46124
46629
|
if (!config && !previewMode) {
|
|
46125
|
-
console.log('[ChatWidget] Not rendering - config not loaded yet');
|
|
46126
46630
|
return null;
|
|
46127
46631
|
}
|
|
46128
|
-
console.log('[ChatWidget] Rendering widget', { isOpen, hasConfig: !!config });
|
|
46129
46632
|
// Get button icon based on state
|
|
46130
46633
|
const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
|
|
46131
46634
|
return (jsxRuntimeExports.jsx("div", { ref: containerRef, className: `ai-chat-widget ${effectiveTheme}`, style: mergedStyles, children: jsxRuntimeExports.jsxs("div", { ref: widgetRef, className: `ai-chat-widget-container ${effectivePosition}`, children: [isOpen && (jsxRuntimeExports.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage, onClose: handleToggle, onFeedback: handleFeedback,
|