@chatwidgetai/chat-widget 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-chat-widget.umd.js +144 -219
- package/dist/ai-chat-widget.umd.js.map +1 -1
- package/dist/api/client.d.ts +9 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/components/ChatWidget.d.ts.map +1 -1
- package/dist/components/ChatWindow.d.ts +0 -2
- package/dist/components/ChatWindow.d.ts.map +1 -1
- package/dist/hooks/useChat.d.ts +0 -10
- package/dist/hooks/useChat.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +145 -220
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +145 -219
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/utils/actionExecutor.d.ts +0 -18
- package/dist/utils/actionExecutor.d.ts.map +0 -1
|
@@ -44141,6 +44141,65 @@
|
|
|
44141
44141
|
* API Client for Widget Communication
|
|
44142
44142
|
* Handles all HTTP requests to the widget API
|
|
44143
44143
|
*/
|
|
44144
|
+
class ApiError extends Error {
|
|
44145
|
+
constructor(message, status, options) {
|
|
44146
|
+
super(message);
|
|
44147
|
+
this.name = 'ApiError';
|
|
44148
|
+
this.status = status;
|
|
44149
|
+
this.details = options?.details;
|
|
44150
|
+
this.retryAfterMs = options?.retryAfterMs;
|
|
44151
|
+
}
|
|
44152
|
+
}
|
|
44153
|
+
function parseRetryAfter(headerValue) {
|
|
44154
|
+
if (!headerValue)
|
|
44155
|
+
return undefined;
|
|
44156
|
+
const seconds = Number(headerValue);
|
|
44157
|
+
if (!Number.isNaN(seconds) && seconds >= 0) {
|
|
44158
|
+
return seconds * 1000;
|
|
44159
|
+
}
|
|
44160
|
+
const date = Date.parse(headerValue);
|
|
44161
|
+
if (!Number.isNaN(date)) {
|
|
44162
|
+
return Math.max(0, date - Date.now());
|
|
44163
|
+
}
|
|
44164
|
+
return undefined;
|
|
44165
|
+
}
|
|
44166
|
+
async function buildApiError(response, defaultMessage) {
|
|
44167
|
+
let parsedBody = null;
|
|
44168
|
+
let message = defaultMessage;
|
|
44169
|
+
try {
|
|
44170
|
+
const raw = await response.text();
|
|
44171
|
+
if (raw) {
|
|
44172
|
+
try {
|
|
44173
|
+
parsedBody = JSON.parse(raw);
|
|
44174
|
+
if (typeof parsedBody === 'object' && parsedBody !== null) {
|
|
44175
|
+
const body = parsedBody;
|
|
44176
|
+
message = typeof body.error === 'string'
|
|
44177
|
+
? body.error
|
|
44178
|
+
: typeof body.message === 'string'
|
|
44179
|
+
? body.message
|
|
44180
|
+
: defaultMessage;
|
|
44181
|
+
}
|
|
44182
|
+
else {
|
|
44183
|
+
message = raw;
|
|
44184
|
+
}
|
|
44185
|
+
}
|
|
44186
|
+
catch {
|
|
44187
|
+
message = raw;
|
|
44188
|
+
}
|
|
44189
|
+
}
|
|
44190
|
+
}
|
|
44191
|
+
catch {
|
|
44192
|
+
// ignore body parsing errors
|
|
44193
|
+
}
|
|
44194
|
+
let retryAfterMs = parseRetryAfter(response.headers.get('retry-after'));
|
|
44195
|
+
if (retryAfterMs === undefined) {
|
|
44196
|
+
retryAfterMs = parseRetryAfter(response.headers.get('x-ratelimit-reset'));
|
|
44197
|
+
}
|
|
44198
|
+
return new ApiError(message || defaultMessage, response.status, {
|
|
44199
|
+
details: parsedBody,
|
|
44200
|
+
retryAfterMs,
|
|
44201
|
+
});
|
|
44202
|
+
}
|
|
44144
44203
|
class WidgetApiClient {
|
|
44145
44204
|
constructor(config) {
|
|
44146
44205
|
this.config = config;
|
|
@@ -44157,23 +44216,24 @@
|
|
|
44157
44216
|
},
|
|
44158
44217
|
});
|
|
44159
44218
|
if (!response.ok) {
|
|
44160
|
-
throw
|
|
44219
|
+
throw await buildApiError(response, 'Failed to fetch config');
|
|
44161
44220
|
}
|
|
44162
44221
|
const json = await response.json();
|
|
44163
44222
|
return json;
|
|
44164
44223
|
}
|
|
44165
44224
|
async getOrCreateConversation(conversationId) {
|
|
44166
|
-
const
|
|
44225
|
+
const baseUrl = `${this.config.apiUrl}/api/widget/${this.config.widgetId}/conversation`;
|
|
44226
|
+
const query = conversationId ? `?conversationId=${encodeURIComponent(conversationId)}` : '';
|
|
44227
|
+
const response = await fetch(`${baseUrl}${query}`, {
|
|
44167
44228
|
method: 'GET',
|
|
44168
44229
|
headers: {
|
|
44169
44230
|
'Authorization': `Bearer ${this.config.apiKey}`,
|
|
44170
|
-
}
|
|
44231
|
+
},
|
|
44171
44232
|
});
|
|
44172
44233
|
if (!response.ok) {
|
|
44173
|
-
|
|
44174
|
-
throw new Error(error.error || 'Failed to upload file');
|
|
44234
|
+
throw await buildApiError(response, 'Failed to load conversation');
|
|
44175
44235
|
}
|
|
44176
|
-
return
|
|
44236
|
+
return response.json();
|
|
44177
44237
|
}
|
|
44178
44238
|
/**
|
|
44179
44239
|
* Upload a file
|
|
@@ -44190,8 +44250,7 @@
|
|
|
44190
44250
|
body: formData,
|
|
44191
44251
|
});
|
|
44192
44252
|
if (!response.ok) {
|
|
44193
|
-
|
|
44194
|
-
throw new Error(error.error || 'Failed to upload file');
|
|
44253
|
+
throw await buildApiError(response, 'Failed to upload file');
|
|
44195
44254
|
}
|
|
44196
44255
|
const result = await response.json();
|
|
44197
44256
|
return result.file;
|
|
@@ -44214,8 +44273,7 @@
|
|
|
44214
44273
|
}),
|
|
44215
44274
|
});
|
|
44216
44275
|
if (!response.ok) {
|
|
44217
|
-
|
|
44218
|
-
throw new Error(error.error || 'Failed to send message');
|
|
44276
|
+
throw await buildApiError(response, 'Failed to send message');
|
|
44219
44277
|
}
|
|
44220
44278
|
return response.json();
|
|
44221
44279
|
}
|
|
@@ -44237,8 +44295,7 @@
|
|
|
44237
44295
|
}),
|
|
44238
44296
|
});
|
|
44239
44297
|
if (!response.ok) {
|
|
44240
|
-
|
|
44241
|
-
throw new Error(error.error || `Agent request failed with status ${response.status}`);
|
|
44298
|
+
throw await buildApiError(response, `Agent request failed with status ${response.status}`);
|
|
44242
44299
|
}
|
|
44243
44300
|
const data = await response.json();
|
|
44244
44301
|
// Check if response indicates an error
|
|
@@ -44250,7 +44307,7 @@
|
|
|
44250
44307
|
catch (error) {
|
|
44251
44308
|
// Enhance error messages
|
|
44252
44309
|
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
44253
|
-
throw new
|
|
44310
|
+
throw new ApiError('Network error: Unable to reach the server', 0);
|
|
44254
44311
|
}
|
|
44255
44312
|
throw error;
|
|
44256
44313
|
}
|
|
@@ -44272,13 +44329,13 @@
|
|
|
44272
44329
|
}),
|
|
44273
44330
|
});
|
|
44274
44331
|
if (!response.ok) {
|
|
44275
|
-
const
|
|
44332
|
+
const apiError = await buildApiError(response, 'Failed to submit feedback');
|
|
44276
44333
|
console.error('Feedback submission failed:', {
|
|
44277
44334
|
status: response.status,
|
|
44278
|
-
error:
|
|
44335
|
+
error: apiError.details,
|
|
44279
44336
|
payload: { session_id: sessionId, message_id: messageId, feedback }
|
|
44280
44337
|
});
|
|
44281
|
-
throw
|
|
44338
|
+
throw apiError;
|
|
44282
44339
|
}
|
|
44283
44340
|
}
|
|
44284
44341
|
/**
|
|
@@ -44386,111 +44443,70 @@
|
|
|
44386
44443
|
}
|
|
44387
44444
|
|
|
44388
44445
|
/**
|
|
44389
|
-
*
|
|
44390
|
-
*
|
|
44391
|
-
*/
|
|
44392
|
-
/**
|
|
44393
|
-
* Execute a client-side action
|
|
44446
|
+
* useChat Hook
|
|
44447
|
+
* Main state management for chat functionality
|
|
44394
44448
|
*/
|
|
44395
|
-
|
|
44396
|
-
|
|
44397
|
-
|
|
44398
|
-
|
|
44399
|
-
|
|
44400
|
-
|
|
44401
|
-
|
|
44402
|
-
|
|
44403
|
-
case
|
|
44404
|
-
|
|
44405
|
-
|
|
44406
|
-
|
|
44449
|
+
function deriveErrorInfo(error) {
|
|
44450
|
+
if (error instanceof ApiError) {
|
|
44451
|
+
const retryAfterSeconds = typeof error.retryAfterMs === 'number'
|
|
44452
|
+
? Math.max(1, Math.ceil(error.retryAfterMs / 1000))
|
|
44453
|
+
: undefined;
|
|
44454
|
+
const lowerMessage = (error.message || '').toLowerCase();
|
|
44455
|
+
let message;
|
|
44456
|
+
switch (error.status) {
|
|
44457
|
+
case 429: {
|
|
44458
|
+
const isPerUser = lowerMessage.includes('user');
|
|
44459
|
+
const base = isPerUser
|
|
44460
|
+
? 'You have reached the per-user rate limit.'
|
|
44461
|
+
: 'This widget has received too many requests.';
|
|
44462
|
+
if (retryAfterSeconds) {
|
|
44463
|
+
message = `${base} Please wait ${retryAfterSeconds} second${retryAfterSeconds === 1 ? '' : 's'} before trying again.`;
|
|
44464
|
+
}
|
|
44465
|
+
else {
|
|
44466
|
+
message = `${base} Please wait a moment and try again.`;
|
|
44467
|
+
}
|
|
44468
|
+
break;
|
|
44469
|
+
}
|
|
44470
|
+
case 401:
|
|
44471
|
+
message = 'Authentication failed. Please refresh the page or verify your API key.';
|
|
44472
|
+
break;
|
|
44473
|
+
case 403:
|
|
44474
|
+
message = 'Access to this widget is restricted. Please contact the site owner if you believe this is an error.';
|
|
44475
|
+
break;
|
|
44476
|
+
case 404:
|
|
44477
|
+
message = 'We could not find this widget. It may have been removed.';
|
|
44478
|
+
break;
|
|
44407
44479
|
default:
|
|
44408
|
-
|
|
44409
|
-
|
|
44410
|
-
|
|
44411
|
-
|
|
44412
|
-
|
|
44480
|
+
if (error.status >= 500) {
|
|
44481
|
+
message = 'The server encountered an error. Please try again shortly.';
|
|
44482
|
+
}
|
|
44483
|
+
else if (error.status > 0) {
|
|
44484
|
+
message = error.message || 'Something went wrong. Please try again.';
|
|
44485
|
+
}
|
|
44486
|
+
else {
|
|
44487
|
+
message = error.message || 'Unable to connect to the server. Please check your internet connection.';
|
|
44488
|
+
}
|
|
44413
44489
|
}
|
|
44490
|
+
return { message, retryAfterSeconds, status: error.status };
|
|
44414
44491
|
}
|
|
44415
|
-
|
|
44416
|
-
|
|
44417
|
-
|
|
44418
|
-
|
|
44419
|
-
|
|
44420
|
-
|
|
44421
|
-
|
|
44422
|
-
|
|
44423
|
-
|
|
44424
|
-
|
|
44425
|
-
|
|
44426
|
-
|
|
44427
|
-
|
|
44428
|
-
|
|
44429
|
-
return {
|
|
44430
|
-
}
|
|
44431
|
-
try {
|
|
44432
|
-
// Validate URL
|
|
44433
|
-
new URL(url);
|
|
44434
|
-
// Redirect
|
|
44435
|
-
window.location.href = url;
|
|
44436
|
-
return { success: true, result: { redirected_to: url } };
|
|
44437
|
-
}
|
|
44438
|
-
catch (error) {
|
|
44439
|
-
return { success: false, error: 'Invalid URL' };
|
|
44440
|
-
}
|
|
44441
|
-
}
|
|
44442
|
-
/**
|
|
44443
|
-
* Show a modal
|
|
44444
|
-
*/
|
|
44445
|
-
function executeShowModal(params) {
|
|
44446
|
-
const { title, content } = params;
|
|
44447
|
-
if (!title || !content) {
|
|
44448
|
-
return { success: false, error: 'Title and content are required' };
|
|
44449
|
-
}
|
|
44450
|
-
// Use browser's alert as a simple modal
|
|
44451
|
-
// In a real implementation, you'd use a proper modal component
|
|
44452
|
-
alert(`${title}\n\n${content}`);
|
|
44453
|
-
return { success: true, result: { shown: true } };
|
|
44454
|
-
}
|
|
44455
|
-
/**
|
|
44456
|
-
* Copy text to clipboard
|
|
44457
|
-
*/
|
|
44458
|
-
async function executeCopyToClipboard(params) {
|
|
44459
|
-
const text = params.text;
|
|
44460
|
-
if (!text) {
|
|
44461
|
-
return { success: false, error: 'Text parameter is required' };
|
|
44462
|
-
}
|
|
44463
|
-
try {
|
|
44464
|
-
await navigator.clipboard.writeText(text);
|
|
44465
|
-
return { success: true, result: { copied: text } };
|
|
44466
|
-
}
|
|
44467
|
-
catch (error) {
|
|
44468
|
-
return {
|
|
44469
|
-
success: false,
|
|
44470
|
-
error: 'Failed to copy to clipboard. Please check browser permissions.'
|
|
44471
|
-
};
|
|
44472
|
-
}
|
|
44473
|
-
}
|
|
44474
|
-
/**
|
|
44475
|
-
* Open chat with a specific message
|
|
44476
|
-
*/
|
|
44477
|
-
function executeOpenChat(params) {
|
|
44478
|
-
const message = params.message;
|
|
44479
|
-
if (!message) {
|
|
44480
|
-
return { success: false, error: 'Message parameter is required' };
|
|
44492
|
+
if (error instanceof Error) {
|
|
44493
|
+
const lower = error.message.toLowerCase();
|
|
44494
|
+
if (lower.includes('network')) {
|
|
44495
|
+
return { message: 'Unable to connect to the server. Please check your internet connection.' };
|
|
44496
|
+
}
|
|
44497
|
+
if (lower.includes('timeout')) {
|
|
44498
|
+
return { message: 'The request timed out. Please try again.' };
|
|
44499
|
+
}
|
|
44500
|
+
if (lower.includes('unauthorized') || lower.includes('401')) {
|
|
44501
|
+
return { message: 'Authentication failed. Please refresh the page or verify your API key.' };
|
|
44502
|
+
}
|
|
44503
|
+
if (lower.includes('internal server error') || lower.includes('500')) {
|
|
44504
|
+
return { message: 'The server encountered an error. Please try again shortly.' };
|
|
44505
|
+
}
|
|
44506
|
+
return { message: error.message || 'Something went wrong. Please try again.' };
|
|
44481
44507
|
}
|
|
44482
|
-
|
|
44483
|
-
const event = new CustomEvent('widget:open-chat', {
|
|
44484
|
-
detail: { message }
|
|
44485
|
-
});
|
|
44486
|
-
window.dispatchEvent(event);
|
|
44487
|
-
return { success: true, result: { message } };
|
|
44508
|
+
return { message: 'Something went wrong. Please try again.' };
|
|
44488
44509
|
}
|
|
44489
|
-
|
|
44490
|
-
/**
|
|
44491
|
-
* useChat Hook
|
|
44492
|
-
* Main state management for chat functionality
|
|
44493
|
-
*/
|
|
44494
44510
|
function useChat(options) {
|
|
44495
44511
|
const { widgetId, apiKey, apiUrl, onMessage, onError, } = options;
|
|
44496
44512
|
const [state, setState] = reactExports.useState({
|
|
@@ -44502,7 +44518,6 @@
|
|
|
44502
44518
|
conversationId: '', // Will be set after loading conversation
|
|
44503
44519
|
config: null,
|
|
44504
44520
|
});
|
|
44505
|
-
const [pendingAction, setPendingAction] = reactExports.useState(null);
|
|
44506
44521
|
const apiClient = reactExports.useRef(new WidgetApiClient({ widgetId, apiKey, apiUrl }));
|
|
44507
44522
|
// Load configuration and conversation on mount
|
|
44508
44523
|
reactExports.useEffect(() => {
|
|
@@ -44527,8 +44542,9 @@
|
|
|
44527
44542
|
}));
|
|
44528
44543
|
}
|
|
44529
44544
|
catch (error) {
|
|
44530
|
-
const
|
|
44531
|
-
|
|
44545
|
+
const errorInfo = deriveErrorInfo(error);
|
|
44546
|
+
const err = error instanceof Error ? error : new Error(errorInfo.message);
|
|
44547
|
+
setState(prev => ({ ...prev, error: errorInfo.message }));
|
|
44532
44548
|
onError?.(err);
|
|
44533
44549
|
}
|
|
44534
44550
|
};
|
|
@@ -44583,7 +44599,6 @@
|
|
|
44583
44599
|
}
|
|
44584
44600
|
// Determine if widget has actions (use agent endpoint)
|
|
44585
44601
|
const useAgent = state.config?.behavior.agentic || (state.config?.actions && state.config.actions.length > 0);
|
|
44586
|
-
console.log(useAgent);
|
|
44587
44602
|
let response;
|
|
44588
44603
|
if (useAgent) {
|
|
44589
44604
|
// Use agent endpoint - returns ConversationMessage[]
|
|
@@ -44652,26 +44667,9 @@
|
|
|
44652
44667
|
}
|
|
44653
44668
|
}
|
|
44654
44669
|
catch (error) {
|
|
44655
|
-
const
|
|
44656
|
-
|
|
44657
|
-
let userMessage = err.message;
|
|
44658
|
-
// Handle specific error types
|
|
44659
|
-
if (err.message.includes('Network') || err.message.includes('fetch')) {
|
|
44660
|
-
userMessage = 'Unable to connect to the server. Please check your internet connection.';
|
|
44661
|
-
}
|
|
44662
|
-
else if (err.message.includes('401') || err.message.includes('Unauthorized')) {
|
|
44663
|
-
userMessage = 'Authentication failed. Please refresh the page.';
|
|
44664
|
-
}
|
|
44665
|
-
else if (err.message.includes('500') || err.message.includes('Internal Server Error')) {
|
|
44666
|
-
userMessage = 'The server encountered an error. Please try again later.';
|
|
44667
|
-
}
|
|
44668
|
-
else if (err.message.includes('timeout')) {
|
|
44669
|
-
userMessage = 'Request timed out. Please try again.';
|
|
44670
|
-
}
|
|
44671
|
-
// Use fallback message if configured, otherwise use error message
|
|
44670
|
+
const errorInfo = deriveErrorInfo(error);
|
|
44671
|
+
const err = error instanceof Error ? error : new Error(errorInfo.message);
|
|
44672
44672
|
const fallbackMessage = state.config?.behavior?.fallbackMessage;
|
|
44673
|
-
const errorMessage = fallbackMessage || userMessage;
|
|
44674
|
-
// If fallback message is configured, add it as an assistant message
|
|
44675
44673
|
if (fallbackMessage) {
|
|
44676
44674
|
const fallbackAssistantMessage = {
|
|
44677
44675
|
id: generateMessageId(),
|
|
@@ -44687,17 +44685,16 @@
|
|
|
44687
44685
|
messages: [...prev.messages, fallbackAssistantMessage],
|
|
44688
44686
|
isLoading: false,
|
|
44689
44687
|
isTyping: false,
|
|
44690
|
-
error:
|
|
44688
|
+
error: errorInfo.message,
|
|
44691
44689
|
}));
|
|
44692
44690
|
onMessage?.(fallbackAssistantMessage);
|
|
44693
44691
|
}
|
|
44694
44692
|
else {
|
|
44695
|
-
// Show error message as assistant message for better UX
|
|
44696
44693
|
const errorAssistantMessage = {
|
|
44697
44694
|
id: generateMessageId(),
|
|
44698
44695
|
message: {
|
|
44699
44696
|
type: 'ai',
|
|
44700
|
-
content: `⚠️ ${
|
|
44697
|
+
content: `⚠️ ${errorInfo.message}`,
|
|
44701
44698
|
},
|
|
44702
44699
|
timestamp: new Date().toISOString(),
|
|
44703
44700
|
sources: [],
|
|
@@ -44707,7 +44704,7 @@
|
|
|
44707
44704
|
messages: [...prev.messages, errorAssistantMessage],
|
|
44708
44705
|
isLoading: false,
|
|
44709
44706
|
isTyping: false,
|
|
44710
|
-
error:
|
|
44707
|
+
error: errorInfo.message,
|
|
44711
44708
|
}));
|
|
44712
44709
|
onMessage?.(errorAssistantMessage);
|
|
44713
44710
|
}
|
|
@@ -44745,81 +44742,12 @@
|
|
|
44745
44742
|
}));
|
|
44746
44743
|
}
|
|
44747
44744
|
catch (error) {
|
|
44748
|
-
const
|
|
44745
|
+
const errorInfo = deriveErrorInfo(error);
|
|
44746
|
+
const err = error instanceof Error ? error : new Error(errorInfo.message);
|
|
44747
|
+
setState(prev => ({ ...prev, error: errorInfo.message }));
|
|
44749
44748
|
onError?.(err);
|
|
44750
44749
|
}
|
|
44751
44750
|
}, [state.conversationId, onError]);
|
|
44752
|
-
/**
|
|
44753
|
-
* Approve and execute pending action
|
|
44754
|
-
*/
|
|
44755
|
-
const approveAction = reactExports.useCallback(async () => {
|
|
44756
|
-
if (!pendingAction)
|
|
44757
|
-
return;
|
|
44758
|
-
setState(prev => ({ ...prev, isLoading: true, isTyping: true }));
|
|
44759
|
-
try {
|
|
44760
|
-
// Execute the client action
|
|
44761
|
-
const actionResult = await executeClientAction(pendingAction.action);
|
|
44762
|
-
// Update the pending action message to show execution result
|
|
44763
|
-
const executionMessage = actionResult.success
|
|
44764
|
-
? `✓ Action executed successfully`
|
|
44765
|
-
: `✗ Action failed: ${actionResult.error}`;
|
|
44766
|
-
setState(prev => ({
|
|
44767
|
-
...prev,
|
|
44768
|
-
messages: prev.messages.map(msg => msg.id === pendingAction.messageId
|
|
44769
|
-
? { ...msg, message: { ...msg.message, content: `${msg.message.content}\n\n${executionMessage}` } }
|
|
44770
|
-
: msg),
|
|
44771
|
-
}));
|
|
44772
|
-
// Clear pending action
|
|
44773
|
-
setPendingAction(null);
|
|
44774
|
-
// TODO: Implement continueAgent in API client if actions are needed
|
|
44775
|
-
// For now, just show success message
|
|
44776
|
-
const assistantMessage = {
|
|
44777
|
-
id: generateMessageId(),
|
|
44778
|
-
message: {
|
|
44779
|
-
type: 'ai',
|
|
44780
|
-
content: 'Action completed successfully.',
|
|
44781
|
-
},
|
|
44782
|
-
timestamp: new Date().toISOString(),
|
|
44783
|
-
sources: [],
|
|
44784
|
-
};
|
|
44785
|
-
setState(prev => ({
|
|
44786
|
-
...prev,
|
|
44787
|
-
messages: [...prev.messages, assistantMessage],
|
|
44788
|
-
isLoading: false,
|
|
44789
|
-
isTyping: false,
|
|
44790
|
-
}));
|
|
44791
|
-
onMessage?.(assistantMessage);
|
|
44792
|
-
}
|
|
44793
|
-
catch (error) {
|
|
44794
|
-
const err = error instanceof Error ? error : new Error('Failed to execute action');
|
|
44795
|
-
setState(prev => ({
|
|
44796
|
-
...prev,
|
|
44797
|
-
isLoading: false,
|
|
44798
|
-
isTyping: false,
|
|
44799
|
-
error: err.message,
|
|
44800
|
-
messages: prev.messages.map(msg => msg.id === pendingAction.messageId
|
|
44801
|
-
? { ...msg, message: { ...msg.message, content: `${msg.message.content}\n\n✗ Failed to execute action` } }
|
|
44802
|
-
: msg),
|
|
44803
|
-
}));
|
|
44804
|
-
setPendingAction(null);
|
|
44805
|
-
onError?.(err);
|
|
44806
|
-
}
|
|
44807
|
-
}, [pendingAction, state.conversationId, onMessage, onError]);
|
|
44808
|
-
/**
|
|
44809
|
-
* Reject pending action
|
|
44810
|
-
*/
|
|
44811
|
-
const rejectAction = reactExports.useCallback(() => {
|
|
44812
|
-
if (!pendingAction)
|
|
44813
|
-
return;
|
|
44814
|
-
// Update message to show rejection
|
|
44815
|
-
setState(prev => ({
|
|
44816
|
-
...prev,
|
|
44817
|
-
messages: prev.messages.map(msg => msg.id === pendingAction.messageId
|
|
44818
|
-
? { ...msg, message: { ...msg.message, content: `${msg.message.content}\n\n✗ Action cancelled by user` } }
|
|
44819
|
-
: msg),
|
|
44820
|
-
}));
|
|
44821
|
-
setPendingAction(null);
|
|
44822
|
-
}, [pendingAction]);
|
|
44823
44751
|
return {
|
|
44824
44752
|
messages: state.messages,
|
|
44825
44753
|
isLoading: state.isLoading,
|
|
@@ -44827,10 +44755,7 @@
|
|
|
44827
44755
|
error: state.error,
|
|
44828
44756
|
config: state.config,
|
|
44829
44757
|
conversationId: state.conversationId,
|
|
44830
|
-
pendingAction,
|
|
44831
44758
|
sendMessage,
|
|
44832
|
-
approveAction,
|
|
44833
|
-
rejectAction,
|
|
44834
44759
|
clearMessages,
|
|
44835
44760
|
submitFeedback,
|
|
44836
44761
|
};
|
|
@@ -65741,7 +65666,7 @@
|
|
|
65741
65666
|
|
|
65742
65667
|
const ChatWidget = ({ widgetId, apiKey, apiUrl = window.location.origin, position = 'bottom-right', theme: themeOverride, primaryColor, onOpen, onClose, onMessage, onError, }) => {
|
|
65743
65668
|
const [isOpen, setIsOpen] = reactExports.useState(false);
|
|
65744
|
-
const { messages, isLoading, isTyping, error, config, sendMessage,
|
|
65669
|
+
const { messages, isLoading, isTyping, error, config, sendMessage, submitFeedback, } = useChat({
|
|
65745
65670
|
widgetId,
|
|
65746
65671
|
apiKey,
|
|
65747
65672
|
apiUrl,
|
|
@@ -65791,7 +65716,7 @@
|
|
|
65791
65716
|
const handleFeedback = async (messageId, feedback) => {
|
|
65792
65717
|
await submitFeedback(messageId, feedback);
|
|
65793
65718
|
};
|
|
65794
|
-
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-widget ${effectiveTheme}`, style: customStyles, children: jsxRuntimeExports.jsx("div", { className: `ai-chat-widget-container ${effectivePosition}`, children: isOpen ? (jsxRuntimeExports.jsx(ChatWindow, { messages: messages, isLoading: isLoading, isTyping: isTyping, error: error, config: config, onSendMessage: sendMessage,
|
|
65719
|
+
return (jsxRuntimeExports.jsx("div", { className: `ai-chat-widget ${effectiveTheme}`, style: customStyles, children: jsxRuntimeExports.jsx("div", { 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 })) : (jsxRuntimeExports.jsx("button", { className: "ai-chat-button", onClick: handleToggle, "aria-label": "Open chat", style: {
|
|
65795
65720
|
width: config?.appearance.buttonSize || 60,
|
|
65796
65721
|
height: config?.appearance.buttonSize || 60,
|
|
65797
65722
|
}, children: config?.appearance.buttonIcon ? (jsxRuntimeExports.jsx("span", { className: "ai-chat-button-icon", children: config.appearance.buttonIcon })) : (jsxRuntimeExports.jsx("svg", { className: "ai-chat-button-svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntimeExports.jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })) })) }) }));
|