@chatwidgetai/chat-widget 0.2.3 → 0.2.5
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 -307
- package/dist/ai-chat-widget.umd.js.map +1 -1
- package/dist/api/client.d.ts +8 -27
- 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 -307
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +803 -307
- 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,13 +17341,53 @@
|
|
|
17341
17341
|
|
|
17342
17342
|
var jsxRuntimeExports = requireJsxRuntime();
|
|
17343
17343
|
|
|
17344
|
-
|
|
17345
|
-
|
|
17346
|
-
|
|
17347
|
-
|
|
17348
|
-
|
|
17349
|
-
|
|
17350
|
-
|
|
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
|
+
|
|
17351
17391
|
class ApiError extends Error {
|
|
17352
17392
|
constructor(message, status, options) {
|
|
17353
17393
|
super(message);
|
|
@@ -17476,12 +17516,8 @@
|
|
|
17476
17516
|
const result = await response.json();
|
|
17477
17517
|
return result.file;
|
|
17478
17518
|
}
|
|
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`, {
|
|
17519
|
+
async *sendAgentMessageStream(conversationId, message, fileIds) {
|
|
17520
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent`, {
|
|
17485
17521
|
method: 'POST',
|
|
17486
17522
|
headers: {
|
|
17487
17523
|
'Content-Type': 'application/json',
|
|
@@ -17494,167 +17530,36 @@
|
|
|
17494
17530
|
}),
|
|
17495
17531
|
});
|
|
17496
17532
|
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;
|
|
17533
|
+
throw await buildApiError(response, 'Failed to send agent message');
|
|
17534
17534
|
}
|
|
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
|
-
}),
|
|
17535
|
+
yield* parseSSEStream(response, (data) => {
|
|
17536
|
+
return typeof data === 'object' && data !== null && 'type' in data;
|
|
17551
17537
|
});
|
|
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
17538
|
}
|
|
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`, {
|
|
17539
|
+
async *continueAgentMessageStream(conversationId, toolCallId, state) {
|
|
17540
|
+
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/agent/continue`, {
|
|
17600
17541
|
method: 'POST',
|
|
17601
17542
|
headers: {
|
|
17602
17543
|
'Content-Type': 'application/json',
|
|
17603
17544
|
},
|
|
17604
17545
|
body: JSON.stringify({
|
|
17605
17546
|
conversationId: conversationId,
|
|
17606
|
-
|
|
17607
|
-
|
|
17547
|
+
toolCallId,
|
|
17548
|
+
state,
|
|
17608
17549
|
timeZone: this.getTimeZone(),
|
|
17609
17550
|
}),
|
|
17610
17551
|
});
|
|
17611
17552
|
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();
|
|
17553
|
+
throw await buildApiError(response, 'Failed to continue agent');
|
|
17652
17554
|
}
|
|
17555
|
+
yield* parseSSEStream(response, (data) => {
|
|
17556
|
+
return typeof data === 'object' && data !== null && 'type' in data;
|
|
17557
|
+
});
|
|
17653
17558
|
}
|
|
17654
17559
|
/**
|
|
17655
17560
|
* Submit feedback for a message
|
|
17656
17561
|
*/
|
|
17657
|
-
async submitFeedback(sessionId, messageId, feedback) {
|
|
17562
|
+
async submitFeedback(sessionId, messageId, feedback, meta) {
|
|
17658
17563
|
const response = await fetch(`${this.config.apiUrl}/api/widget/${this.config.widgetId}/feedback`, {
|
|
17659
17564
|
method: 'POST',
|
|
17660
17565
|
headers: {
|
|
@@ -17664,6 +17569,9 @@
|
|
|
17664
17569
|
conversationId: sessionId,
|
|
17665
17570
|
messageId: messageId,
|
|
17666
17571
|
feedback,
|
|
17572
|
+
messageRole: meta?.role,
|
|
17573
|
+
messageContent: meta?.content,
|
|
17574
|
+
messageTimestamp: meta?.timestamp,
|
|
17667
17575
|
}),
|
|
17668
17576
|
});
|
|
17669
17577
|
if (!response.ok) {
|
|
@@ -17714,6 +17622,173 @@
|
|
|
17714
17622
|
return `msg_${timestamp}_${randomStr}`;
|
|
17715
17623
|
}
|
|
17716
17624
|
|
|
17625
|
+
const pendingResolvers = new Map();
|
|
17626
|
+
const resumeCallbacks = new Map();
|
|
17627
|
+
const frontendActionHandlers = {};
|
|
17628
|
+
const actionRenderers = {};
|
|
17629
|
+
function getFrontendActionHandler(implementation) {
|
|
17630
|
+
return frontendActionHandlers[implementation];
|
|
17631
|
+
}
|
|
17632
|
+
function getActionRenderer(implementation) {
|
|
17633
|
+
return actionRenderers[implementation];
|
|
17634
|
+
}
|
|
17635
|
+
function getActionPrompt(implementation) {
|
|
17636
|
+
if (implementation === "google-calendar-appointment") {
|
|
17637
|
+
return "Select a date to continue.";
|
|
17638
|
+
}
|
|
17639
|
+
return "Action input required.";
|
|
17640
|
+
}
|
|
17641
|
+
function waitForActionState(toolCallId) {
|
|
17642
|
+
return new Promise((resolve) => {
|
|
17643
|
+
pendingResolvers.set(toolCallId, resolve);
|
|
17644
|
+
});
|
|
17645
|
+
}
|
|
17646
|
+
function resolveActionState(toolCallId, state) {
|
|
17647
|
+
const resolver = pendingResolvers.get(toolCallId);
|
|
17648
|
+
if (resolver) {
|
|
17649
|
+
pendingResolvers.delete(toolCallId);
|
|
17650
|
+
resolver(state);
|
|
17651
|
+
return;
|
|
17652
|
+
}
|
|
17653
|
+
// If no active resolver, check for a resume callback (for page reload scenario)
|
|
17654
|
+
const resumeCallback = resumeCallbacks.get(toolCallId);
|
|
17655
|
+
if (resumeCallback) {
|
|
17656
|
+
resumeCallback(state).catch((error) => {
|
|
17657
|
+
console.error("[Action] Failed to resume action:", error);
|
|
17658
|
+
});
|
|
17659
|
+
}
|
|
17660
|
+
}
|
|
17661
|
+
function registerActionResumeCallback(toolCallId, callback) {
|
|
17662
|
+
resumeCallbacks.set(toolCallId, callback);
|
|
17663
|
+
}
|
|
17664
|
+
function unregisterActionResumeCallback(toolCallId) {
|
|
17665
|
+
resumeCallbacks.delete(toolCallId);
|
|
17666
|
+
}
|
|
17667
|
+
|
|
17668
|
+
function groupSlotsByDate(slots) {
|
|
17669
|
+
const grouped = new Map();
|
|
17670
|
+
for (const slot of slots) {
|
|
17671
|
+
if (!slot || typeof slot !== 'object' || !slot.startTime || typeof slot.startTime !== 'string') {
|
|
17672
|
+
continue;
|
|
17673
|
+
}
|
|
17674
|
+
const date = slot.startTime.slice(0, 10);
|
|
17675
|
+
if (!grouped.has(date)) {
|
|
17676
|
+
grouped.set(date, []);
|
|
17677
|
+
}
|
|
17678
|
+
grouped.get(date).push(slot);
|
|
17679
|
+
}
|
|
17680
|
+
return grouped;
|
|
17681
|
+
}
|
|
17682
|
+
function formatDate(dateStr) {
|
|
17683
|
+
try {
|
|
17684
|
+
const date = new Date(dateStr);
|
|
17685
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
17686
|
+
weekday: "short",
|
|
17687
|
+
month: "short",
|
|
17688
|
+
day: "numeric",
|
|
17689
|
+
}).format(date);
|
|
17690
|
+
}
|
|
17691
|
+
catch {
|
|
17692
|
+
return dateStr;
|
|
17693
|
+
}
|
|
17694
|
+
}
|
|
17695
|
+
function GoogleCalendarAppointmentCard({ message }) {
|
|
17696
|
+
const action = message.action;
|
|
17697
|
+
if (!action || action.implementation !== "google-calendar-appointment") {
|
|
17698
|
+
return null;
|
|
17699
|
+
}
|
|
17700
|
+
const rawSlots = action.state.availableSlots;
|
|
17701
|
+
const availableSlots = Array.isArray(rawSlots)
|
|
17702
|
+
? rawSlots.filter((slot) => slot !== null &&
|
|
17703
|
+
slot !== undefined &&
|
|
17704
|
+
typeof slot === "object" &&
|
|
17705
|
+
"startTime" in slot &&
|
|
17706
|
+
"endTime" in slot &&
|
|
17707
|
+
typeof slot.startTime === "string" &&
|
|
17708
|
+
typeof slot.endTime === "string")
|
|
17709
|
+
: [];
|
|
17710
|
+
const allowTopic = action.state.allowTopic !== false;
|
|
17711
|
+
const isBooked = action.state.status === "booked";
|
|
17712
|
+
const slotsByDate = groupSlotsByDate(availableSlots);
|
|
17713
|
+
const dates = Array.from(slotsByDate.keys()).sort();
|
|
17714
|
+
const [selectedDate, setSelectedDate] = reactExports.useState(dates[0] ?? "");
|
|
17715
|
+
const [selectedSlot, setSelectedSlot] = reactExports.useState(null);
|
|
17716
|
+
const [topic, setTopic] = reactExports.useState("");
|
|
17717
|
+
const [error, setError] = reactExports.useState(null);
|
|
17718
|
+
const slotsForSelectedDate = selectedDate ? slotsByDate.get(selectedDate) ?? [] : [];
|
|
17719
|
+
const onConfirm = () => {
|
|
17720
|
+
if (!selectedSlot) {
|
|
17721
|
+
setError("Please select a time slot.");
|
|
17722
|
+
return;
|
|
17723
|
+
}
|
|
17724
|
+
if (allowTopic && !topic.trim()) {
|
|
17725
|
+
setError("Please enter a topic for the meeting.");
|
|
17726
|
+
return;
|
|
17727
|
+
}
|
|
17728
|
+
setError(null);
|
|
17729
|
+
resolveActionState(action.toolCallId, {
|
|
17730
|
+
...action.state,
|
|
17731
|
+
selectedSlot: {
|
|
17732
|
+
startTime: selectedSlot.startTime,
|
|
17733
|
+
endTime: selectedSlot.endTime,
|
|
17734
|
+
},
|
|
17735
|
+
topic: allowTopic ? topic.trim() : null,
|
|
17736
|
+
});
|
|
17737
|
+
};
|
|
17738
|
+
if (isBooked) {
|
|
17739
|
+
const rawBookedSlot = action.state.selectedSlot;
|
|
17740
|
+
const bookedSlot = rawBookedSlot &&
|
|
17741
|
+
typeof rawBookedSlot === "object" &&
|
|
17742
|
+
"startTime" in rawBookedSlot &&
|
|
17743
|
+
"endTime" in rawBookedSlot
|
|
17744
|
+
? rawBookedSlot
|
|
17745
|
+
: null;
|
|
17746
|
+
const bookedTopic = typeof action.state.topic === "string" ? action.state.topic : null;
|
|
17747
|
+
const eventLink = typeof action.state.bookedEventLink === "string" ? action.state.bookedEventLink : null;
|
|
17748
|
+
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" }))] })] }));
|
|
17749
|
+
}
|
|
17750
|
+
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: () => {
|
|
17751
|
+
setSelectedDate(date);
|
|
17752
|
+
setSelectedSlot(null);
|
|
17753
|
+
}, 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." }))] })] }));
|
|
17754
|
+
}
|
|
17755
|
+
|
|
17756
|
+
frontendActionHandlers["google-calendar-appointment"] = async (_input, _state, context) => {
|
|
17757
|
+
return waitForActionState(context.toolCallId);
|
|
17758
|
+
};
|
|
17759
|
+
|
|
17760
|
+
function styleInject(css, ref) {
|
|
17761
|
+
if ( ref === void 0 ) ref = {};
|
|
17762
|
+
var insertAt = ref.insertAt;
|
|
17763
|
+
|
|
17764
|
+
if (!css || typeof document === 'undefined') { return; }
|
|
17765
|
+
|
|
17766
|
+
var head = document.head || document.getElementsByTagName('head')[0];
|
|
17767
|
+
var style = document.createElement('style');
|
|
17768
|
+
style.type = 'text/css';
|
|
17769
|
+
|
|
17770
|
+
if (insertAt === 'top') {
|
|
17771
|
+
if (head.firstChild) {
|
|
17772
|
+
head.insertBefore(style, head.firstChild);
|
|
17773
|
+
} else {
|
|
17774
|
+
head.appendChild(style);
|
|
17775
|
+
}
|
|
17776
|
+
} else {
|
|
17777
|
+
head.appendChild(style);
|
|
17778
|
+
}
|
|
17779
|
+
|
|
17780
|
+
if (style.styleSheet) {
|
|
17781
|
+
style.styleSheet.cssText = css;
|
|
17782
|
+
} else {
|
|
17783
|
+
style.appendChild(document.createTextNode(css));
|
|
17784
|
+
}
|
|
17785
|
+
}
|
|
17786
|
+
|
|
17787
|
+
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)}";
|
|
17788
|
+
styleInject(css_248z$1);
|
|
17789
|
+
|
|
17790
|
+
actionRenderers["google-calendar-appointment"] = (message) => (jsxRuntimeExports.jsx(GoogleCalendarAppointmentCard, { message: message }));
|
|
17791
|
+
|
|
17717
17792
|
/**
|
|
17718
17793
|
* Local Storage Utilities
|
|
17719
17794
|
* Handles conversation persistence in browser localStorage
|
|
@@ -17775,9 +17850,12 @@
|
|
|
17775
17850
|
* Get preview text from messages
|
|
17776
17851
|
*/
|
|
17777
17852
|
function getConversationPreview(messages) {
|
|
17778
|
-
const firstUserMessage = messages.find(m => m.message.
|
|
17853
|
+
const firstUserMessage = messages.find(m => m.message.role === "user");
|
|
17779
17854
|
if (firstUserMessage) {
|
|
17780
|
-
|
|
17855
|
+
const content = typeof firstUserMessage.message.content === "string"
|
|
17856
|
+
? firstUserMessage.message.content
|
|
17857
|
+
: "";
|
|
17858
|
+
return content.slice(0, 100);
|
|
17781
17859
|
}
|
|
17782
17860
|
return 'New conversation';
|
|
17783
17861
|
}
|
|
@@ -17932,6 +18010,473 @@
|
|
|
17932
18010
|
* useChat Hook
|
|
17933
18011
|
* Main state management for chat functionality
|
|
17934
18012
|
*/
|
|
18013
|
+
function hydrateToolNames(messages) {
|
|
18014
|
+
const toolCallNameById = new Map();
|
|
18015
|
+
for (const entry of messages) {
|
|
18016
|
+
if (entry.message.role !== "assistant") {
|
|
18017
|
+
continue;
|
|
18018
|
+
}
|
|
18019
|
+
const toolCalls = entry.message.tool_calls;
|
|
18020
|
+
if (!Array.isArray(toolCalls)) {
|
|
18021
|
+
continue;
|
|
18022
|
+
}
|
|
18023
|
+
for (const call of toolCalls) {
|
|
18024
|
+
const callId = call?.id;
|
|
18025
|
+
const callName = call?.function?.name;
|
|
18026
|
+
if (callId && callName) {
|
|
18027
|
+
toolCallNameById.set(callId, callName);
|
|
18028
|
+
}
|
|
18029
|
+
}
|
|
18030
|
+
}
|
|
18031
|
+
if (toolCallNameById.size === 0) {
|
|
18032
|
+
return messages;
|
|
18033
|
+
}
|
|
18034
|
+
return messages.map((entry) => {
|
|
18035
|
+
if (entry.message.role !== "tool") {
|
|
18036
|
+
return entry;
|
|
18037
|
+
}
|
|
18038
|
+
const toolCallId = entry.message.tool_call_id;
|
|
18039
|
+
const resolvedName = toolCallNameById.get(toolCallId);
|
|
18040
|
+
if (!resolvedName) {
|
|
18041
|
+
return entry;
|
|
18042
|
+
}
|
|
18043
|
+
const currentName = entry.message.name;
|
|
18044
|
+
const nextName = currentName && currentName.trim().length > 0 ? currentName : resolvedName;
|
|
18045
|
+
const nextToolExecuting = entry.toolExecuting || resolvedName;
|
|
18046
|
+
if (nextName === currentName && nextToolExecuting === entry.toolExecuting) {
|
|
18047
|
+
return entry;
|
|
18048
|
+
}
|
|
18049
|
+
return {
|
|
18050
|
+
...entry,
|
|
18051
|
+
message: { ...entry.message, name: nextName },
|
|
18052
|
+
toolExecuting: nextToolExecuting,
|
|
18053
|
+
};
|
|
18054
|
+
});
|
|
18055
|
+
}
|
|
18056
|
+
function hydrateActionContent(messages) {
|
|
18057
|
+
return messages.map((entry) => {
|
|
18058
|
+
if (entry.message.role !== "assistant" || !entry.action) {
|
|
18059
|
+
return entry;
|
|
18060
|
+
}
|
|
18061
|
+
const content = typeof entry.message.content === "string" ? entry.message.content : "";
|
|
18062
|
+
if (content.trim().length > 0) {
|
|
18063
|
+
return entry;
|
|
18064
|
+
}
|
|
18065
|
+
return {
|
|
18066
|
+
...entry,
|
|
18067
|
+
message: { ...entry.message, content: getActionPrompt(entry.action.implementation) },
|
|
18068
|
+
};
|
|
18069
|
+
});
|
|
18070
|
+
}
|
|
18071
|
+
function hydrateMessages(messages) {
|
|
18072
|
+
return hydrateActionContent(hydrateToolNames(messages));
|
|
18073
|
+
}
|
|
18074
|
+
function setupActionResumeCallbacks(messages, client, conversationId, setState, onMessageUpdate) {
|
|
18075
|
+
// Find all incomplete actions and register resume callbacks
|
|
18076
|
+
for (const message of messages) {
|
|
18077
|
+
if (message.action && !message.action.done) {
|
|
18078
|
+
const toolCallId = message.action.toolCallId;
|
|
18079
|
+
const toolName = message.message.name || message.toolExecuting || "tool";
|
|
18080
|
+
registerActionResumeCallback(toolCallId, async (newState) => {
|
|
18081
|
+
// When user interacts with the action after reload, continue the stream
|
|
18082
|
+
try {
|
|
18083
|
+
// Update the action message with the new state
|
|
18084
|
+
setState(prev => ({
|
|
18085
|
+
...prev,
|
|
18086
|
+
messages: prev.messages.map(m => m.action?.toolCallId === toolCallId
|
|
18087
|
+
? {
|
|
18088
|
+
...m,
|
|
18089
|
+
action: m.action ? { ...m.action, state: newState } : undefined,
|
|
18090
|
+
}
|
|
18091
|
+
: m),
|
|
18092
|
+
isTyping: true,
|
|
18093
|
+
}));
|
|
18094
|
+
const streamState = createStreamState();
|
|
18095
|
+
// Continue the agent stream with the new state
|
|
18096
|
+
for await (const event of client.continueAgentMessageStream(conversationId, toolCallId, newState)) {
|
|
18097
|
+
if (event.type === "done") {
|
|
18098
|
+
finalizeToolMessage(streamState, setState, toolCallId, toolName);
|
|
18099
|
+
streamState.sources = event.sources;
|
|
18100
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
18101
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
|
|
18102
|
+
continue;
|
|
18103
|
+
}
|
|
18104
|
+
if (event.type === "error") {
|
|
18105
|
+
const errorMessage = {
|
|
18106
|
+
id: generateMessageId(),
|
|
18107
|
+
message: {
|
|
18108
|
+
role: "assistant",
|
|
18109
|
+
content: `Error: ${event.error}`,
|
|
18110
|
+
},
|
|
18111
|
+
timestamp: new Date().toISOString(),
|
|
18112
|
+
sources: [],
|
|
18113
|
+
isError: true,
|
|
18114
|
+
};
|
|
18115
|
+
upsertMessage(setState, errorMessage, false);
|
|
18116
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
18117
|
+
return;
|
|
18118
|
+
}
|
|
18119
|
+
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
18120
|
+
}
|
|
18121
|
+
setState(prev => ({ ...prev, isTyping: false }));
|
|
18122
|
+
}
|
|
18123
|
+
catch (error) {
|
|
18124
|
+
console.error("[Action Resume] Failed to continue stream:", error);
|
|
18125
|
+
setState(prev => ({ ...prev, isTyping: false, error: error instanceof Error ? error.message : "Failed to resume action" }));
|
|
18126
|
+
throw error;
|
|
18127
|
+
}
|
|
18128
|
+
});
|
|
18129
|
+
}
|
|
18130
|
+
}
|
|
18131
|
+
}
|
|
18132
|
+
function createStreamState() {
|
|
18133
|
+
return {
|
|
18134
|
+
currentContent: "",
|
|
18135
|
+
currentMessageId: generateMessageId(),
|
|
18136
|
+
activeToolCallCount: 0,
|
|
18137
|
+
newMessageIds: new Set(),
|
|
18138
|
+
sources: [],
|
|
18139
|
+
toolCallToActionId: {},
|
|
18140
|
+
};
|
|
18141
|
+
}
|
|
18142
|
+
function upsertMessage(setState, message, isTyping) {
|
|
18143
|
+
setState(prev => {
|
|
18144
|
+
const existingIndex = prev.messages.findIndex(m => m.id === message.id);
|
|
18145
|
+
if (existingIndex >= 0) {
|
|
18146
|
+
const newMessages = [...prev.messages];
|
|
18147
|
+
newMessages[existingIndex] = message;
|
|
18148
|
+
return { ...prev, messages: newMessages, isTyping, isLoading: false };
|
|
18149
|
+
}
|
|
18150
|
+
return {
|
|
18151
|
+
...prev,
|
|
18152
|
+
messages: [...prev.messages, message],
|
|
18153
|
+
isTyping,
|
|
18154
|
+
isLoading: false,
|
|
18155
|
+
};
|
|
18156
|
+
});
|
|
18157
|
+
}
|
|
18158
|
+
function finalizeStreamMessages(setState, messageIds, sources, toolCallToActionId) {
|
|
18159
|
+
setState(prev => ({
|
|
18160
|
+
...prev,
|
|
18161
|
+
messages: prev.messages.map(msg => (messageIds.has(msg.id)
|
|
18162
|
+
? { ...msg, sources, toolCallToActionId }
|
|
18163
|
+
: msg)),
|
|
18164
|
+
isTyping: false,
|
|
18165
|
+
}));
|
|
18166
|
+
}
|
|
18167
|
+
function handleContentEvent(event, streamState, onMessageUpdate, setState) {
|
|
18168
|
+
streamState.currentContent += event.content;
|
|
18169
|
+
const assistantMessage = {
|
|
18170
|
+
id: streamState.currentMessageId,
|
|
18171
|
+
message: { role: "assistant", content: streamState.currentContent },
|
|
18172
|
+
timestamp: new Date().toISOString(),
|
|
18173
|
+
sources: streamState.sources,
|
|
18174
|
+
isStreaming: true,
|
|
18175
|
+
};
|
|
18176
|
+
streamState.newMessageIds.add(assistantMessage.id);
|
|
18177
|
+
onMessageUpdate(assistantMessage);
|
|
18178
|
+
const hasContent = assistantMessage.message.content?.trim().length || 0 > 0;
|
|
18179
|
+
const isToolExecuting = streamState.activeToolCallCount > 0;
|
|
18180
|
+
const isTyping = (!hasContent && assistantMessage.isStreaming) || isToolExecuting;
|
|
18181
|
+
upsertMessage(setState, assistantMessage, isTyping);
|
|
18182
|
+
}
|
|
18183
|
+
function handleToolStartEvent(event, streamState, onMessageUpdate, setState) {
|
|
18184
|
+
if (streamState.currentContent.trim()) {
|
|
18185
|
+
const finalAssistant = {
|
|
18186
|
+
id: streamState.currentMessageId,
|
|
18187
|
+
message: { role: "assistant", content: streamState.currentContent },
|
|
18188
|
+
timestamp: new Date().toISOString(),
|
|
18189
|
+
sources: streamState.sources,
|
|
18190
|
+
isStreaming: false,
|
|
18191
|
+
};
|
|
18192
|
+
streamState.newMessageIds.add(finalAssistant.id);
|
|
18193
|
+
onMessageUpdate(finalAssistant);
|
|
18194
|
+
upsertMessage(setState, finalAssistant, true);
|
|
18195
|
+
streamState.currentContent = "";
|
|
18196
|
+
streamState.currentMessageId = generateMessageId();
|
|
18197
|
+
}
|
|
18198
|
+
const toolMessageId = event.tool_call_id;
|
|
18199
|
+
streamState.activeToolCallCount += 1;
|
|
18200
|
+
streamState.newMessageIds.add(toolMessageId);
|
|
18201
|
+
const toolMessage = {
|
|
18202
|
+
id: toolMessageId,
|
|
18203
|
+
sources: [],
|
|
18204
|
+
message: { role: "tool", content: "", tool_call_id: event.tool_call_id, name: event.tool_name },
|
|
18205
|
+
timestamp: new Date().toISOString(),
|
|
18206
|
+
isStreaming: true,
|
|
18207
|
+
toolExecuting: event.tool_name,
|
|
18208
|
+
};
|
|
18209
|
+
upsertMessage(setState, toolMessage, true);
|
|
18210
|
+
}
|
|
18211
|
+
function handleToolEndEvent(event, streamState, _onMessageUpdate, setState) {
|
|
18212
|
+
// Update state and mark action as done in a single setState call
|
|
18213
|
+
setState(prev => {
|
|
18214
|
+
const messages = prev.messages.map((msg) => {
|
|
18215
|
+
const matchesToolCall = msg.message.role === "tool" && msg.message.tool_call_id === event.tool_call_id;
|
|
18216
|
+
if (!matchesToolCall) {
|
|
18217
|
+
return msg;
|
|
18218
|
+
}
|
|
18219
|
+
const existingName = msg.message.name || event.tool_name;
|
|
18220
|
+
return {
|
|
18221
|
+
...msg,
|
|
18222
|
+
message: {
|
|
18223
|
+
role: "tool",
|
|
18224
|
+
content: event.state ? JSON.stringify(event.state) : (typeof msg.message.content === "string" ? msg.message.content : ""),
|
|
18225
|
+
tool_call_id: event.tool_call_id,
|
|
18226
|
+
name: existingName,
|
|
18227
|
+
},
|
|
18228
|
+
isStreaming: false,
|
|
18229
|
+
toolExecuting: existingName,
|
|
18230
|
+
action: msg.action ? {
|
|
18231
|
+
...msg.action,
|
|
18232
|
+
state: event.state || msg.action.state,
|
|
18233
|
+
done: true, // Mark action as completed
|
|
18234
|
+
} : undefined,
|
|
18235
|
+
};
|
|
18236
|
+
});
|
|
18237
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
18238
|
+
});
|
|
18239
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
18240
|
+
}
|
|
18241
|
+
function handleToolErrorEvent(event, streamState, _onMessageUpdate, setState) {
|
|
18242
|
+
setState(prev => {
|
|
18243
|
+
const messages = prev.messages.map((entry) => {
|
|
18244
|
+
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === event.tool_call_id;
|
|
18245
|
+
if (!matchesToolCall) {
|
|
18246
|
+
return entry;
|
|
18247
|
+
}
|
|
18248
|
+
const name = entry.message.name || "tool";
|
|
18249
|
+
const toolMessage = {
|
|
18250
|
+
...entry,
|
|
18251
|
+
message: {
|
|
18252
|
+
role: "tool",
|
|
18253
|
+
content: event.error || "Tool execution failed",
|
|
18254
|
+
tool_call_id: event.tool_call_id,
|
|
18255
|
+
name,
|
|
18256
|
+
},
|
|
18257
|
+
timestamp: new Date().toISOString(),
|
|
18258
|
+
isStreaming: false,
|
|
18259
|
+
isError: true,
|
|
18260
|
+
toolExecuting: name,
|
|
18261
|
+
};
|
|
18262
|
+
return toolMessage;
|
|
18263
|
+
});
|
|
18264
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
18265
|
+
});
|
|
18266
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
18267
|
+
}
|
|
18268
|
+
function finalizeToolMessage(streamState, setState, toolCallId, toolName) {
|
|
18269
|
+
setState(prev => {
|
|
18270
|
+
const messages = prev.messages.map((entry) => {
|
|
18271
|
+
const matchesToolCall = entry.message.role === "tool" && entry.message.tool_call_id === toolCallId;
|
|
18272
|
+
if (!matchesToolCall) {
|
|
18273
|
+
return entry;
|
|
18274
|
+
}
|
|
18275
|
+
const existingName = entry.message.name || toolName;
|
|
18276
|
+
return {
|
|
18277
|
+
...entry,
|
|
18278
|
+
message: {
|
|
18279
|
+
role: "tool",
|
|
18280
|
+
content: typeof entry.message.content === "string" ? entry.message.content : "",
|
|
18281
|
+
tool_call_id: toolCallId,
|
|
18282
|
+
name: existingName,
|
|
18283
|
+
},
|
|
18284
|
+
isStreaming: false,
|
|
18285
|
+
toolExecuting: existingName,
|
|
18286
|
+
action: entry.action ? {
|
|
18287
|
+
...entry.action,
|
|
18288
|
+
done: true, // Mark action as completed
|
|
18289
|
+
} : undefined,
|
|
18290
|
+
};
|
|
18291
|
+
});
|
|
18292
|
+
return { ...prev, messages, isTyping: false, isLoading: false };
|
|
18293
|
+
});
|
|
18294
|
+
streamState.activeToolCallCount = Math.max(0, streamState.activeToolCallCount - 1);
|
|
18295
|
+
}
|
|
18296
|
+
function handleDoneEvent(event, streamState, _onMessageUpdate, setState) {
|
|
18297
|
+
streamState.sources = event.sources;
|
|
18298
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
18299
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
|
|
18300
|
+
}
|
|
18301
|
+
function handleHaltEvent(event, _streamState, onMessageUpdate, setState) {
|
|
18302
|
+
const toolNames = event.tool_calls.map(call => call.name).join(", ");
|
|
18303
|
+
const notice = toolNames
|
|
18304
|
+
? `Awaiting external tool results: ${toolNames}.`
|
|
18305
|
+
: "Awaiting external tool results.";
|
|
18306
|
+
const haltMessage = {
|
|
18307
|
+
id: generateMessageId(),
|
|
18308
|
+
message: { role: "assistant", content: notice },
|
|
18309
|
+
timestamp: new Date().toISOString(),
|
|
18310
|
+
sources: [],
|
|
18311
|
+
isError: true,
|
|
18312
|
+
};
|
|
18313
|
+
onMessageUpdate(haltMessage);
|
|
18314
|
+
upsertMessage(setState, haltMessage, false);
|
|
18315
|
+
setState(prev => ({ ...prev, error: "Awaiting external tool handling." }));
|
|
18316
|
+
}
|
|
18317
|
+
function handleErrorEvent(event, _streamState, onMessageUpdate, setState) {
|
|
18318
|
+
const errorMessage = {
|
|
18319
|
+
id: generateMessageId(),
|
|
18320
|
+
message: { role: "assistant", content: `⚠️ ${event.error}` },
|
|
18321
|
+
timestamp: new Date().toISOString(),
|
|
18322
|
+
sources: [],
|
|
18323
|
+
isError: true,
|
|
18324
|
+
};
|
|
18325
|
+
onMessageUpdate(errorMessage);
|
|
18326
|
+
upsertMessage(setState, errorMessage, false);
|
|
18327
|
+
setState(prev => ({ ...prev, error: event.error }));
|
|
18328
|
+
}
|
|
18329
|
+
const eventHandlers = {
|
|
18330
|
+
content: handleContentEvent,
|
|
18331
|
+
tool_start: handleToolStartEvent,
|
|
18332
|
+
tool_end: handleToolEndEvent,
|
|
18333
|
+
tool_error: handleToolErrorEvent,
|
|
18334
|
+
done: handleDoneEvent,
|
|
18335
|
+
halt: handleHaltEvent,
|
|
18336
|
+
error: handleErrorEvent,
|
|
18337
|
+
action_request: () => { },
|
|
18338
|
+
};
|
|
18339
|
+
function handleStreamEvent(event, streamState, onMessageUpdate, setState) {
|
|
18340
|
+
if (event.type === "tool_start" || event.type === "tool_end" || event.type === "tool_error" || event.type === "action_request" || event.type === "done" || event.type === "halt") {
|
|
18341
|
+
console.log("[Widget] stream event:", {
|
|
18342
|
+
type: event.type,
|
|
18343
|
+
toolCallId: "tool_call_id" in event ? event.tool_call_id : undefined,
|
|
18344
|
+
toolName: "tool_name" in event ? event.tool_name : undefined,
|
|
18345
|
+
});
|
|
18346
|
+
}
|
|
18347
|
+
const handler = eventHandlers[event.type];
|
|
18348
|
+
if (handler) {
|
|
18349
|
+
handler(event, streamState, onMessageUpdate, setState);
|
|
18350
|
+
}
|
|
18351
|
+
else {
|
|
18352
|
+
console.warn('[Chat] Unknown event type:', event.type);
|
|
18353
|
+
}
|
|
18354
|
+
}
|
|
18355
|
+
async function handleActionLoop(client, initialEvent, streamState, onMessageUpdate, setState, widgetId, conversationId, getMessages) {
|
|
18356
|
+
let pendingEvent = initialEvent;
|
|
18357
|
+
while (pendingEvent) {
|
|
18358
|
+
streamState.toolCallToActionId = pendingEvent.tool_call_to_action_id;
|
|
18359
|
+
const resumeToolCallId = pendingEvent.tool_call_id;
|
|
18360
|
+
const existingToolMessage = getMessages().find((entry) => entry.message.role === "tool" && entry.message.tool_call_id === resumeToolCallId);
|
|
18361
|
+
const toolMessageId = existingToolMessage?.id ?? resumeToolCallId;
|
|
18362
|
+
const toolName = existingToolMessage?.message.name ?? "tool";
|
|
18363
|
+
const toolMessage = {
|
|
18364
|
+
id: toolMessageId,
|
|
18365
|
+
sources: [],
|
|
18366
|
+
message: {
|
|
18367
|
+
role: "tool",
|
|
18368
|
+
content: "",
|
|
18369
|
+
tool_call_id: resumeToolCallId,
|
|
18370
|
+
name: toolName,
|
|
18371
|
+
},
|
|
18372
|
+
timestamp: new Date().toISOString(),
|
|
18373
|
+
isStreaming: true,
|
|
18374
|
+
toolExecuting: toolName,
|
|
18375
|
+
action: {
|
|
18376
|
+
implementation: pendingEvent.implementation,
|
|
18377
|
+
toolCallId: pendingEvent.tool_call_id,
|
|
18378
|
+
actionId: pendingEvent.action_id,
|
|
18379
|
+
input: pendingEvent.input,
|
|
18380
|
+
state: pendingEvent.state,
|
|
18381
|
+
done: false, // Action not yet completed
|
|
18382
|
+
},
|
|
18383
|
+
};
|
|
18384
|
+
if (streamState.activeToolCallCount === 0) {
|
|
18385
|
+
streamState.activeToolCallCount = 1;
|
|
18386
|
+
}
|
|
18387
|
+
onMessageUpdate(toolMessage);
|
|
18388
|
+
upsertMessage(setState, toolMessage, true);
|
|
18389
|
+
const handler = getFrontendActionHandler(pendingEvent.implementation);
|
|
18390
|
+
if (!handler) {
|
|
18391
|
+
const errorMessage = {
|
|
18392
|
+
id: generateMessageId(),
|
|
18393
|
+
message: {
|
|
18394
|
+
role: "assistant",
|
|
18395
|
+
content: `⚠️ No frontend handler for action '${pendingEvent.implementation}'.`,
|
|
18396
|
+
},
|
|
18397
|
+
timestamp: new Date().toISOString(),
|
|
18398
|
+
sources: [],
|
|
18399
|
+
isError: true,
|
|
18400
|
+
};
|
|
18401
|
+
onMessageUpdate(errorMessage);
|
|
18402
|
+
upsertMessage(setState, errorMessage, false);
|
|
18403
|
+
setState(prev => ({ ...prev, error: `Missing frontend handler: ${pendingEvent?.implementation}` }));
|
|
18404
|
+
return;
|
|
18405
|
+
}
|
|
18406
|
+
let nextState;
|
|
18407
|
+
try {
|
|
18408
|
+
nextState = await handler(pendingEvent.input, pendingEvent.state, {
|
|
18409
|
+
widgetId,
|
|
18410
|
+
conversationId,
|
|
18411
|
+
toolCallId: pendingEvent.tool_call_id,
|
|
18412
|
+
actionId: pendingEvent.action_id,
|
|
18413
|
+
implementation: pendingEvent.implementation,
|
|
18414
|
+
});
|
|
18415
|
+
}
|
|
18416
|
+
catch (error) {
|
|
18417
|
+
const errorMessage = error instanceof Error ? error.message : "Frontend action failed.";
|
|
18418
|
+
const errorMessageEntry = {
|
|
18419
|
+
id: generateMessageId(),
|
|
18420
|
+
message: { role: "assistant", content: `⚠️ ${errorMessage}` },
|
|
18421
|
+
timestamp: new Date().toISOString(),
|
|
18422
|
+
sources: [],
|
|
18423
|
+
isError: true,
|
|
18424
|
+
};
|
|
18425
|
+
onMessageUpdate(errorMessageEntry);
|
|
18426
|
+
upsertMessage(setState, errorMessageEntry, false);
|
|
18427
|
+
setState(prev => ({ ...prev, error: errorMessage }));
|
|
18428
|
+
return;
|
|
18429
|
+
}
|
|
18430
|
+
pendingEvent = null;
|
|
18431
|
+
const updatedToolMessage = {
|
|
18432
|
+
...toolMessage,
|
|
18433
|
+
action: toolMessage.action
|
|
18434
|
+
? {
|
|
18435
|
+
...toolMessage.action,
|
|
18436
|
+
state: nextState,
|
|
18437
|
+
}
|
|
18438
|
+
: undefined,
|
|
18439
|
+
};
|
|
18440
|
+
upsertMessage(setState, updatedToolMessage, true);
|
|
18441
|
+
let streamEnded = false;
|
|
18442
|
+
for await (const event of client.continueAgentMessageStream(conversationId, resumeToolCallId, nextState)) {
|
|
18443
|
+
if (event.type === "action_request") {
|
|
18444
|
+
pendingEvent = event;
|
|
18445
|
+
break;
|
|
18446
|
+
}
|
|
18447
|
+
if (event.type === "done") {
|
|
18448
|
+
// Don't extract and update state from done event - the state was already
|
|
18449
|
+
// updated by tool_end event or by the user's frontend action.
|
|
18450
|
+
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
18451
|
+
// Handle the done event but skip the tool finalization part since we already did it
|
|
18452
|
+
streamState.sources = event.sources;
|
|
18453
|
+
streamState.toolCallToActionId = event.tool_call_to_action_id;
|
|
18454
|
+
finalizeStreamMessages(setState, streamState.newMessageIds, event.sources, event.tool_call_to_action_id);
|
|
18455
|
+
streamEnded = true;
|
|
18456
|
+
continue; // Skip handleStreamEvent for done events to avoid state conflicts
|
|
18457
|
+
}
|
|
18458
|
+
if (event.type === "error") {
|
|
18459
|
+
const errorMessage = {
|
|
18460
|
+
id: generateMessageId(),
|
|
18461
|
+
message: {
|
|
18462
|
+
role: "assistant",
|
|
18463
|
+
content: `Error occurred during action execution: ${event.error}`,
|
|
18464
|
+
},
|
|
18465
|
+
timestamp: new Date().toISOString(),
|
|
18466
|
+
sources: [],
|
|
18467
|
+
isError: true,
|
|
18468
|
+
};
|
|
18469
|
+
upsertMessage(setState, errorMessage, false);
|
|
18470
|
+
return;
|
|
18471
|
+
}
|
|
18472
|
+
handleStreamEvent(event, streamState, onMessageUpdate, setState);
|
|
18473
|
+
}
|
|
18474
|
+
// If stream ended without a done event (e.g., only tool_end was sent), finalize the tool message
|
|
18475
|
+
if (!streamEnded && !pendingEvent) {
|
|
18476
|
+
finalizeToolMessage(streamState, setState, resumeToolCallId, toolName);
|
|
18477
|
+
}
|
|
18478
|
+
}
|
|
18479
|
+
}
|
|
17935
18480
|
function deriveErrorInfo(error) {
|
|
17936
18481
|
if (error instanceof ApiError) {
|
|
17937
18482
|
const retryAfterSeconds = typeof error.retryAfterMs === 'number'
|
|
@@ -18004,6 +18549,10 @@
|
|
|
18004
18549
|
conversationId: '', // Will be set after loading conversation
|
|
18005
18550
|
config: null,
|
|
18006
18551
|
});
|
|
18552
|
+
const stateRef = reactExports.useRef(state);
|
|
18553
|
+
reactExports.useEffect(() => {
|
|
18554
|
+
stateRef.current = state;
|
|
18555
|
+
}, [state]);
|
|
18007
18556
|
// Chat history state
|
|
18008
18557
|
const [conversations, setConversations] = reactExports.useState([]);
|
|
18009
18558
|
const apiClient = reactExports.useRef(new WidgetApiClient({ widgetId, apiUrl }));
|
|
@@ -18011,18 +18560,12 @@
|
|
|
18011
18560
|
reactExports.useEffect(() => {
|
|
18012
18561
|
// Skip initialization in preview mode
|
|
18013
18562
|
if (skipInitialization) {
|
|
18014
|
-
console.log('[useChat] Skipping initialization (preview mode)');
|
|
18015
18563
|
return;
|
|
18016
18564
|
}
|
|
18017
18565
|
let isMounted = true;
|
|
18018
|
-
console.log('[useChat] Effect running, mounting component');
|
|
18019
18566
|
const initialize = async () => {
|
|
18020
18567
|
try {
|
|
18021
|
-
console.log('[useChat] Fetching config...');
|
|
18022
18568
|
const config = await apiClient.current.getConfig();
|
|
18023
|
-
console.log('[useChat] Config fetched successfully:', {
|
|
18024
|
-
hasAppearance: !!config.appearance,
|
|
18025
|
-
});
|
|
18026
18569
|
const persistConversation = config.settings.persistConversation ?? true;
|
|
18027
18570
|
let conversationId = '';
|
|
18028
18571
|
let messages = [];
|
|
@@ -18033,7 +18576,7 @@
|
|
|
18033
18576
|
try {
|
|
18034
18577
|
const conversation = await apiClient.current.getOrCreateConversation(storedId);
|
|
18035
18578
|
conversationId = conversation.id;
|
|
18036
|
-
messages = conversation.messages;
|
|
18579
|
+
messages = hydrateMessages(conversation.messages);
|
|
18037
18580
|
}
|
|
18038
18581
|
catch (conversationError) {
|
|
18039
18582
|
console.warn('Failed to load existing conversation:', conversationError);
|
|
@@ -18041,16 +18584,19 @@
|
|
|
18041
18584
|
}
|
|
18042
18585
|
}
|
|
18043
18586
|
if (!isMounted) {
|
|
18044
|
-
console.log('[useChat] Component unmounted, skipping state update');
|
|
18045
18587
|
return;
|
|
18046
18588
|
}
|
|
18047
|
-
|
|
18589
|
+
const hydratedMessages = hydrateMessages(messages);
|
|
18048
18590
|
setState(prev => ({
|
|
18049
18591
|
...prev,
|
|
18050
18592
|
config,
|
|
18051
18593
|
conversationId,
|
|
18052
|
-
messages,
|
|
18594
|
+
messages: hydratedMessages,
|
|
18053
18595
|
}));
|
|
18596
|
+
// Setup resume callbacks for incomplete actions
|
|
18597
|
+
if (conversationId) {
|
|
18598
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversationId, setState, onMessage ?? (() => { }));
|
|
18599
|
+
}
|
|
18054
18600
|
}
|
|
18055
18601
|
catch (error) {
|
|
18056
18602
|
console.error('[useChat] Error fetching config:', error);
|
|
@@ -18065,8 +18611,13 @@
|
|
|
18065
18611
|
};
|
|
18066
18612
|
initialize();
|
|
18067
18613
|
return () => {
|
|
18068
|
-
console.log('[useChat] Effect cleanup, unmounting component');
|
|
18069
18614
|
isMounted = false;
|
|
18615
|
+
// Cleanup resume callbacks
|
|
18616
|
+
state.messages.forEach(message => {
|
|
18617
|
+
if (message.action?.toolCallId) {
|
|
18618
|
+
unregisterActionResumeCallback(message.action.toolCallId);
|
|
18619
|
+
}
|
|
18620
|
+
});
|
|
18070
18621
|
};
|
|
18071
18622
|
}, [widgetId, apiUrl, onError]);
|
|
18072
18623
|
// Save conversation when messages change
|
|
@@ -18079,9 +18630,6 @@
|
|
|
18079
18630
|
saveConversation(widgetId, state.conversationId, state.messages);
|
|
18080
18631
|
}
|
|
18081
18632
|
}, [widgetId, state.messages, state.conversationId, state.config?.settings.persistConversation]);
|
|
18082
|
-
/**
|
|
18083
|
-
* Send a message
|
|
18084
|
-
*/
|
|
18085
18633
|
const sendMessage = reactExports.useCallback(async (content, files) => {
|
|
18086
18634
|
const trimmedContent = content.trim();
|
|
18087
18635
|
const hasFiles = !!files && files.length > 0;
|
|
@@ -18090,7 +18638,7 @@
|
|
|
18090
18638
|
const userMessage = {
|
|
18091
18639
|
id: generateMessageId(),
|
|
18092
18640
|
message: {
|
|
18093
|
-
|
|
18641
|
+
role: "user",
|
|
18094
18642
|
content: trimmedContent,
|
|
18095
18643
|
},
|
|
18096
18644
|
timestamp: new Date().toISOString(),
|
|
@@ -18111,7 +18659,7 @@
|
|
|
18111
18659
|
const conversation = await apiClient.current.getOrCreateConversation();
|
|
18112
18660
|
conversationId = conversation.id;
|
|
18113
18661
|
setState(prev => {
|
|
18114
|
-
const serverMessages = conversation.messages ?? [];
|
|
18662
|
+
const serverMessages = hydrateMessages(conversation.messages ?? []);
|
|
18115
18663
|
if (serverMessages.length === 0) {
|
|
18116
18664
|
return {
|
|
18117
18665
|
...prev,
|
|
@@ -18145,48 +18693,20 @@
|
|
|
18145
18693
|
}
|
|
18146
18694
|
}
|
|
18147
18695
|
}
|
|
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
18696
|
// Stream the response
|
|
18151
18697
|
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
|
-
});
|
|
18698
|
+
const streamState = createStreamState();
|
|
18699
|
+
const stream = apiClient.current.sendAgentMessageStream(conversationId, trimmedContent, fileIds);
|
|
18700
|
+
for await (const event of stream) {
|
|
18701
|
+
if (event.type === "action_request") {
|
|
18702
|
+
await handleActionLoop(apiClient.current, event, streamState, (message) => {
|
|
18703
|
+
lastStreamedMessage = message;
|
|
18704
|
+
}, setState, widgetId, conversationId, () => stateRef.current.messages);
|
|
18705
|
+
break;
|
|
18706
|
+
}
|
|
18707
|
+
handleStreamEvent(event, streamState, (message) => {
|
|
18708
|
+
lastStreamedMessage = message;
|
|
18709
|
+
}, setState);
|
|
18190
18710
|
}
|
|
18191
18711
|
// Stream completed - finalize state
|
|
18192
18712
|
setState(prev => ({
|
|
@@ -18207,7 +18727,7 @@
|
|
|
18207
18727
|
const fallbackAssistantMessage = {
|
|
18208
18728
|
id: generateMessageId(),
|
|
18209
18729
|
message: {
|
|
18210
|
-
|
|
18730
|
+
role: "assistant",
|
|
18211
18731
|
content: fallbackMessage,
|
|
18212
18732
|
},
|
|
18213
18733
|
timestamp: new Date().toISOString(),
|
|
@@ -18226,7 +18746,7 @@
|
|
|
18226
18746
|
const errorAssistantMessage = {
|
|
18227
18747
|
id: generateMessageId(),
|
|
18228
18748
|
message: {
|
|
18229
|
-
|
|
18749
|
+
role: "assistant",
|
|
18230
18750
|
content: `⚠️ ${errorInfo.message}`,
|
|
18231
18751
|
},
|
|
18232
18752
|
timestamp: new Date().toISOString(),
|
|
@@ -18264,8 +18784,13 @@
|
|
|
18264
18784
|
*/
|
|
18265
18785
|
const submitFeedback = reactExports.useCallback(async (messageId, feedback) => {
|
|
18266
18786
|
try {
|
|
18787
|
+
const message = state.messages.find(msg => msg.id === messageId);
|
|
18788
|
+
const messageContent = typeof message?.message.content === "string" ? message.message.content : undefined;
|
|
18789
|
+
const meta = message
|
|
18790
|
+
? { role: message.message.role, content: messageContent, timestamp: message.timestamp }
|
|
18791
|
+
: undefined;
|
|
18267
18792
|
console.log('Submitting feedback:', { conversationId: state.conversationId, messageId, feedback });
|
|
18268
|
-
await apiClient.current.submitFeedback(state.conversationId, messageId, feedback);
|
|
18793
|
+
await apiClient.current.submitFeedback(state.conversationId, messageId, feedback, meta);
|
|
18269
18794
|
// Update message with feedback
|
|
18270
18795
|
setState(prev => ({
|
|
18271
18796
|
...prev,
|
|
@@ -18299,9 +18824,6 @@
|
|
|
18299
18824
|
startedAt: entry.lastUpdated,
|
|
18300
18825
|
})));
|
|
18301
18826
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
18302
|
-
/**
|
|
18303
|
-
* Switch to a different conversation (from localStorage first, then fetch from server if needed)
|
|
18304
|
-
*/
|
|
18305
18827
|
const switchConversation = reactExports.useCallback(async (conversationId) => {
|
|
18306
18828
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
18307
18829
|
// First try to load from localStorage
|
|
@@ -18311,25 +18833,33 @@
|
|
|
18311
18833
|
setState(prev => ({
|
|
18312
18834
|
...prev,
|
|
18313
18835
|
conversationId: stored.conversationId,
|
|
18314
|
-
messages: stored.messages,
|
|
18836
|
+
messages: hydrateMessages(stored.messages),
|
|
18315
18837
|
}));
|
|
18316
18838
|
setActiveConversation(widgetId, conversationId);
|
|
18317
18839
|
return;
|
|
18318
18840
|
}
|
|
18319
18841
|
}
|
|
18320
|
-
// If not in localStorage, fetch from server
|
|
18321
18842
|
setState(prev => ({ ...prev, isLoading: true, error: null }));
|
|
18322
18843
|
try {
|
|
18323
18844
|
const conversation = await apiClient.current.getOrCreateConversation(conversationId);
|
|
18845
|
+
const hydratedMessages = hydrateMessages(conversation.messages);
|
|
18846
|
+
// Clear old resume callbacks
|
|
18847
|
+
state.messages.forEach(message => {
|
|
18848
|
+
if (message.action?.toolCallId) {
|
|
18849
|
+
unregisterActionResumeCallback(message.action.toolCallId);
|
|
18850
|
+
}
|
|
18851
|
+
});
|
|
18324
18852
|
setState(prev => ({
|
|
18325
18853
|
...prev,
|
|
18326
18854
|
conversationId: conversation.id,
|
|
18327
|
-
messages:
|
|
18855
|
+
messages: hydratedMessages,
|
|
18328
18856
|
isLoading: false,
|
|
18329
18857
|
}));
|
|
18858
|
+
// Setup new resume callbacks
|
|
18859
|
+
setupActionResumeCallbacks(hydratedMessages, apiClient.current, conversation.id, setState, onMessage ?? (() => { }));
|
|
18330
18860
|
// Save to local storage
|
|
18331
18861
|
if (persistConversation && isStorageAvailable()) {
|
|
18332
|
-
saveConversation(widgetId, conversation.id,
|
|
18862
|
+
saveConversation(widgetId, conversation.id, hydratedMessages);
|
|
18333
18863
|
}
|
|
18334
18864
|
}
|
|
18335
18865
|
catch (error) {
|
|
@@ -18337,9 +18867,6 @@
|
|
|
18337
18867
|
setState(prev => ({ ...prev, isLoading: false, error: errorInfo.message }));
|
|
18338
18868
|
}
|
|
18339
18869
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
18340
|
-
/**
|
|
18341
|
-
* Start a new conversation (keeps history)
|
|
18342
|
-
*/
|
|
18343
18870
|
const startNewConversation = reactExports.useCallback(() => {
|
|
18344
18871
|
setState(prev => ({
|
|
18345
18872
|
...prev,
|
|
@@ -18347,15 +18874,11 @@
|
|
|
18347
18874
|
conversationId: '',
|
|
18348
18875
|
error: null,
|
|
18349
18876
|
}));
|
|
18350
|
-
// Clear active conversation but keep history
|
|
18351
18877
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
18352
18878
|
if (persistConversation && isStorageAvailable()) {
|
|
18353
18879
|
clearConversation(widgetId);
|
|
18354
18880
|
}
|
|
18355
18881
|
}, [widgetId, state.config?.settings.persistConversation]);
|
|
18356
|
-
/**
|
|
18357
|
-
* Delete a conversation from history
|
|
18358
|
-
*/
|
|
18359
18882
|
const deleteConversation$1 = reactExports.useCallback((conversationId) => {
|
|
18360
18883
|
const persistConversation = state.config?.settings.persistConversation ?? true;
|
|
18361
18884
|
if (!persistConversation || !isStorageAvailable()) {
|
|
@@ -45205,12 +45728,12 @@
|
|
|
45205
45728
|
hour12: true,
|
|
45206
45729
|
});
|
|
45207
45730
|
};
|
|
45208
|
-
const
|
|
45731
|
+
const role = message.message.role;
|
|
45209
45732
|
const isError = message.isError || false;
|
|
45210
|
-
const isTool =
|
|
45211
|
-
const isAssistant =
|
|
45212
|
-
const isSystem =
|
|
45213
|
-
const isHuman =
|
|
45733
|
+
const isTool = role === "tool";
|
|
45734
|
+
const isAssistant = role === "assistant";
|
|
45735
|
+
const isSystem = role === "system";
|
|
45736
|
+
const isHuman = role === "user";
|
|
45214
45737
|
// Tool messages are now handled by ToolMessageGroup in MessageList
|
|
45215
45738
|
if (isTool) {
|
|
45216
45739
|
return null;
|
|
@@ -45221,7 +45744,10 @@
|
|
|
45221
45744
|
const hasContent = aiContent.trim().length > 0;
|
|
45222
45745
|
if (!hasContent)
|
|
45223
45746
|
return null;
|
|
45224
|
-
|
|
45747
|
+
const actionRenderer = message.action
|
|
45748
|
+
? getActionRenderer(message.action.implementation)
|
|
45749
|
+
: undefined;
|
|
45750
|
+
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
45751
|
}
|
|
45226
45752
|
// System message rendering
|
|
45227
45753
|
if (isSystem) {
|
|
@@ -45229,7 +45755,7 @@
|
|
|
45229
45755
|
}
|
|
45230
45756
|
// Human message rendering
|
|
45231
45757
|
if (isHuman) {
|
|
45232
|
-
const userContent = message.message.content.split('--- File Content ---')[0];
|
|
45758
|
+
const userContent = (message.message.content || '').split('--- File Content ---')[0];
|
|
45233
45759
|
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
45760
|
}
|
|
45235
45761
|
return null;
|
|
@@ -45246,13 +45772,31 @@
|
|
|
45246
45772
|
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
45773
|
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
45774
|
const ToolMessageGroup = ({ messages }) => {
|
|
45249
|
-
|
|
45250
|
-
|
|
45251
|
-
|
|
45252
|
-
|
|
45253
|
-
|
|
45254
|
-
|
|
45255
|
-
|
|
45775
|
+
// Check if any message is loading (for actions, check done flag; otherwise check isStreaming)
|
|
45776
|
+
const isAnyLoading = messages.some(m => {
|
|
45777
|
+
if (m.action) {
|
|
45778
|
+
return !(m.action.done ?? false);
|
|
45779
|
+
}
|
|
45780
|
+
return m.isStreaming;
|
|
45781
|
+
});
|
|
45782
|
+
const actionMessages = messages.filter(message => message.action);
|
|
45783
|
+
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) => {
|
|
45784
|
+
const toolName = message.toolExecuting || message.message.name || 'Tool';
|
|
45785
|
+
const hasError = message.isError || false;
|
|
45786
|
+
// For actions, check if done flag is set; otherwise fall back to isStreaming
|
|
45787
|
+
const isDone = message.action ? (message.action.done ?? false) : !message.isStreaming;
|
|
45788
|
+
const isLoading = !isDone;
|
|
45789
|
+
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));
|
|
45790
|
+
}) })] }), actionMessages.map((message) => {
|
|
45791
|
+
if (!message.action) {
|
|
45792
|
+
return null;
|
|
45793
|
+
}
|
|
45794
|
+
const renderer = getActionRenderer(message.action.implementation);
|
|
45795
|
+
if (!renderer) {
|
|
45796
|
+
return null;
|
|
45797
|
+
}
|
|
45798
|
+
return (jsxRuntimeExports.jsx("div", { className: "ai-chat-tool-action", children: renderer(message) }, `action-${message.id}`));
|
|
45799
|
+
})] }));
|
|
45256
45800
|
};
|
|
45257
45801
|
|
|
45258
45802
|
const TypingIndicator = () => {
|
|
@@ -45277,6 +45821,14 @@
|
|
|
45277
45821
|
const MessageList = ({ messages, isTyping = false, showTypingIndicator = true, showTimestamps = true, enableFeedback = true, showSources = true, sourceDisplayMode = 'with-score', welcomeTitle, welcomeMessage, suggestedQuestions, onSuggestedQuestionClick, onFeedback, }) => {
|
|
45278
45822
|
const containerRef = reactExports.useRef(null);
|
|
45279
45823
|
const messagesEndRef = reactExports.useRef(null);
|
|
45824
|
+
// Check if there's an active action awaiting user input
|
|
45825
|
+
const hasActiveAction = reactExports.useMemo(() => {
|
|
45826
|
+
return messages.some(msg => msg.action &&
|
|
45827
|
+
msg.action.state &&
|
|
45828
|
+
msg.action.state.status !== 'completed' &&
|
|
45829
|
+
msg.action.state.status !== 'booked' &&
|
|
45830
|
+
msg.action.state.status !== 'failed');
|
|
45831
|
+
}, [messages]);
|
|
45280
45832
|
// Auto-scroll to bottom only on initial mount/load
|
|
45281
45833
|
reactExports.useEffect(() => {
|
|
45282
45834
|
const container = containerRef.current;
|
|
@@ -45305,16 +45857,16 @@
|
|
|
45305
45857
|
}
|
|
45306
45858
|
};
|
|
45307
45859
|
for (const message of messages) {
|
|
45308
|
-
if (message.message.
|
|
45860
|
+
if (message.message.role === "tool") {
|
|
45309
45861
|
// Add to current tool group
|
|
45310
45862
|
currentToolGroup.push(message);
|
|
45311
45863
|
}
|
|
45312
|
-
else if (message.message.
|
|
45864
|
+
else if (message.message.role === "user") {
|
|
45313
45865
|
// Human message breaks tool grouping
|
|
45314
45866
|
flushToolGroup();
|
|
45315
45867
|
result.push({ type: 'message', message });
|
|
45316
45868
|
}
|
|
45317
|
-
else if (message.message.
|
|
45869
|
+
else if (message.message.role === "assistant") {
|
|
45318
45870
|
// Skip empty AI messages
|
|
45319
45871
|
const content = (message.message.content || '').trim();
|
|
45320
45872
|
if (!content) {
|
|
@@ -45340,7 +45892,7 @@
|
|
|
45340
45892
|
return (jsxRuntimeExports.jsx(ToolMessageGroup, { messages: item.messages }, `tool-group-${index}`));
|
|
45341
45893
|
}
|
|
45342
45894
|
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 })] }));
|
|
45895
|
+
}), isTyping && showTypingIndicator && !hasActiveAction && jsxRuntimeExports.jsx(TypingIndicator, {}), jsxRuntimeExports.jsx("div", { ref: messagesEndRef })] }));
|
|
45344
45896
|
};
|
|
45345
45897
|
|
|
45346
45898
|
// Allowed file types
|
|
@@ -45430,7 +45982,6 @@
|
|
|
45430
45982
|
conversations = [], onLoadConversations, onSwitchConversation, onStartNewConversation, onDeleteConversation, currentConversationId,
|
|
45431
45983
|
// Override props for live preview
|
|
45432
45984
|
headerTitleOverride, welcomeTitleOverride, welcomeMessageOverride, placeholderOverride, suggestedQuestionsOverride, }) => {
|
|
45433
|
-
console.log('[ChatWindow] Rendering ChatWindow component');
|
|
45434
45985
|
const appearance = config?.appearance;
|
|
45435
45986
|
const settings = config?.settings;
|
|
45436
45987
|
// Check if chat history should be shown (requires both persistConversation AND showChatHistory)
|
|
@@ -45441,13 +45992,6 @@
|
|
|
45441
45992
|
const welcomeTitle = welcomeTitleOverride ?? appearance?.welcomeTitle ?? '';
|
|
45442
45993
|
const welcomeMessage = welcomeMessageOverride ?? appearance?.welcomeMessage ?? '';
|
|
45443
45994
|
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
45995
|
// Track if history panel is open
|
|
45452
45996
|
const [showHistory, setShowHistory] = reactExports.useState(false);
|
|
45453
45997
|
// History exit animation when starting a new chat from overview
|
|
@@ -45492,7 +46036,7 @@
|
|
|
45492
46036
|
};
|
|
45493
46037
|
// Check if message limit is reached
|
|
45494
46038
|
const maxMessages = settings?.maxMessagesPerSession;
|
|
45495
|
-
const userMessageCount = messages.filter(m => m.message.
|
|
46039
|
+
const userMessageCount = messages.filter(m => m.message.role === "user").length;
|
|
45496
46040
|
const isLimitReached = maxMessages ? userMessageCount >= maxMessages : false;
|
|
45497
46041
|
const handleQuestionClick = (question) => {
|
|
45498
46042
|
onSendMessage(question);
|
|
@@ -45902,34 +46446,7 @@
|
|
|
45902
46446
|
return observer;
|
|
45903
46447
|
}
|
|
45904
46448
|
|
|
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}";
|
|
46449
|
+
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
46450
|
styleInject(css_248z);
|
|
45934
46451
|
|
|
45935
46452
|
// Icon components mapping
|
|
@@ -46033,16 +46550,6 @@
|
|
|
46033
46550
|
mediaQuery.removeEventListener('change', handleMediaChange);
|
|
46034
46551
|
};
|
|
46035
46552
|
}, [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
46553
|
// Handle auto-open
|
|
46047
46554
|
reactExports.useEffect(() => {
|
|
46048
46555
|
if (config?.settings.autoOpen) {
|
|
@@ -46097,17 +46604,8 @@
|
|
|
46097
46604
|
...customStyles,
|
|
46098
46605
|
...(zIndex !== undefined ? { '--widget-z-index': String(zIndex) } : {}),
|
|
46099
46606
|
};
|
|
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
46607
|
const handleToggle = () => {
|
|
46109
46608
|
const newState = !isOpen;
|
|
46110
|
-
console.log('[ChatWidget] handleToggle called, setting isOpen to:', newState);
|
|
46111
46609
|
setIsOpen(newState);
|
|
46112
46610
|
if (newState) {
|
|
46113
46611
|
onOpen?.();
|
|
@@ -46122,10 +46620,8 @@
|
|
|
46122
46620
|
// Don't render until config is loaded to avoid flash of unstyled content
|
|
46123
46621
|
// In preview mode, config is always available
|
|
46124
46622
|
if (!config && !previewMode) {
|
|
46125
|
-
console.log('[ChatWidget] Not rendering - config not loaded yet');
|
|
46126
46623
|
return null;
|
|
46127
46624
|
}
|
|
46128
|
-
console.log('[ChatWidget] Rendering widget', { isOpen, hasConfig: !!config });
|
|
46129
46625
|
// Get button icon based on state
|
|
46130
46626
|
const IconComponent = isOpen ? iconComponents.FiChevronDown : iconComponents.FiMessageCircle;
|
|
46131
46627
|
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,
|