@makemore/agent-frontend 1.8.0 → 2.0.0
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/README.md +140 -7
- package/dist/chat-widget.css +611 -1
- package/dist/chat-widget.js +305 -1376
- package/package.json +19 -7
- package/src/components/ChatWidget.js +259 -0
- package/src/components/Header.js +111 -0
- package/src/components/InputForm.js +95 -0
- package/src/components/Message.js +115 -0
- package/src/components/MessageList.js +106 -0
- package/src/components/ModelSelector.js +68 -0
- package/src/components/Sidebar.js +58 -0
- package/src/hooks/useChat.js +455 -0
- package/src/hooks/useModels.js +69 -0
- package/src/index.js +222 -0
- package/src/utils/api.js +90 -0
- package/src/utils/config.js +83 -0
- package/src/utils/helpers.js +83 -0
package/dist/chat-widget.js
CHANGED
|
@@ -1,1390 +1,319 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
primaryColor: '#0066cc',
|
|
27
|
-
position: 'bottom-right', // bottom-right, bottom-left
|
|
28
|
-
defaultJourneyType: 'general',
|
|
29
|
-
enableDebugMode: true,
|
|
30
|
-
enableAutoRun: true,
|
|
31
|
-
journeyTypes: {},
|
|
32
|
-
customerPrompts: {},
|
|
33
|
-
placeholder: 'Type your message...',
|
|
34
|
-
emptyStateTitle: 'Start a Conversation',
|
|
35
|
-
emptyStateMessage: 'Send a message to get started.',
|
|
36
|
-
// Authentication configuration
|
|
37
|
-
authStrategy: null, // 'token' | 'jwt' | 'session' | 'anonymous' | 'none' (auto-detected if null)
|
|
38
|
-
authToken: null, // Token value for 'token' or 'jwt' strategies
|
|
39
|
-
authHeader: null, // Custom header name (defaults based on strategy)
|
|
40
|
-
authTokenPrefix: null, // Custom token prefix (defaults based on strategy)
|
|
41
|
-
anonymousSessionEndpoint: null, // Endpoint for anonymous session (defaults to apiPaths.anonymousSession)
|
|
42
|
-
anonymousTokenKey: 'chat_widget_anonymous_token', // Storage key for anonymous token
|
|
43
|
-
onAuthError: null, // Callback for auth errors: (error) => void
|
|
44
|
-
// Legacy config (deprecated but still supported)
|
|
45
|
-
anonymousTokenHeader: 'X-Anonymous-Token',
|
|
46
|
-
conversationIdKey: 'chat_widget_conversation_id',
|
|
47
|
-
sessionTokenKey: 'chat_widget_session_token', // Deprecated: use anonymousTokenKey
|
|
48
|
-
// API endpoint paths (can be customized for different backend setups)
|
|
49
|
-
apiPaths: {
|
|
50
|
-
anonymousSession: '/api/accounts/anonymous-session/',
|
|
51
|
-
runs: '/api/agent-runtime/runs/',
|
|
52
|
-
runEvents: '/api/agent-runtime/runs/{runId}/events/',
|
|
53
|
-
simulateCustomer: '/api/agent-runtime/simulate-customer/',
|
|
54
|
-
ttsVoices: '/api/tts/voices/', // For fetching available voices (proxy mode)
|
|
55
|
-
ttsSetVoice: '/api/tts/set-voice/', // For setting voice (proxy mode)
|
|
56
|
-
},
|
|
57
|
-
// Demo flow control
|
|
58
|
-
autoRunDelay: 1000, // Delay in ms before auto-generating next message
|
|
59
|
-
autoRunMode: 'automatic', // 'automatic', 'confirm', or 'manual'
|
|
60
|
-
// Text-to-speech (ElevenLabs)
|
|
61
|
-
enableTTS: false,
|
|
62
|
-
ttsProxyUrl: null, // If set, uses Django proxy instead of direct API calls
|
|
63
|
-
elevenLabsApiKey: null, // Only needed if not using proxy
|
|
64
|
-
ttsVoices: {
|
|
65
|
-
assistant: null, // ElevenLabs voice ID for assistant (not needed if using proxy)
|
|
66
|
-
user: null, // ElevenLabs voice ID for simulated user (not needed if using proxy)
|
|
67
|
-
},
|
|
68
|
-
ttsModel: 'eleven_turbo_v2_5', // ElevenLabs model (not needed if using proxy)
|
|
69
|
-
ttsSettings: {
|
|
70
|
-
stability: 0.5,
|
|
71
|
-
similarity_boost: 0.75,
|
|
72
|
-
style: 0.0,
|
|
73
|
-
use_speaker_boost: true,
|
|
74
|
-
},
|
|
75
|
-
availableVoices: [], // List of available voices for UI dropdown
|
|
76
|
-
// UI visibility controls
|
|
77
|
-
showClearButton: true,
|
|
78
|
-
showDebugButton: true,
|
|
79
|
-
showTTSButton: true,
|
|
80
|
-
showVoiceSettings: true,
|
|
81
|
-
showExpandButton: true,
|
|
82
|
-
// Event callback
|
|
83
|
-
onEvent: null, // Callback for SSE events: (eventType, payload) => void
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
// State
|
|
87
|
-
let config = { ...DEFAULT_CONFIG };
|
|
88
|
-
let state = {
|
|
89
|
-
isOpen: false,
|
|
90
|
-
isExpanded: false,
|
|
91
|
-
isLoading: false,
|
|
92
|
-
isSimulating: false,
|
|
93
|
-
autoRunActive: false,
|
|
94
|
-
autoRunPaused: false,
|
|
95
|
-
debugMode: false,
|
|
96
|
-
journeyType: 'general',
|
|
97
|
-
messages: [],
|
|
98
|
-
conversationId: null,
|
|
99
|
-
sessionToken: null, // Deprecated: use authToken
|
|
100
|
-
authToken: null, // Current auth token (for token/jwt/anonymous strategies)
|
|
101
|
-
error: null,
|
|
102
|
-
eventSource: null,
|
|
103
|
-
currentAudio: null,
|
|
104
|
-
isSpeaking: false,
|
|
105
|
-
speechQueue: [],
|
|
106
|
-
voiceSettingsOpen: false,
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
// DOM elements
|
|
110
|
-
let container = null;
|
|
111
|
-
let widgetEl = null;
|
|
112
|
-
let fabEl = null;
|
|
113
|
-
|
|
114
|
-
// ============================================================================
|
|
115
|
-
// Utility Functions
|
|
116
|
-
// ============================================================================
|
|
117
|
-
|
|
118
|
-
function generateId() {
|
|
119
|
-
return 'msg-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function escapeHtml(text) {
|
|
123
|
-
const div = document.createElement('div');
|
|
124
|
-
div.textContent = text;
|
|
125
|
-
return div.innerHTML;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function parseMarkdown(text) {
|
|
129
|
-
// Check if enhanced markdown parser is available (from chat-widget-markdown.js)
|
|
130
|
-
if (global.ChatWidget && global.ChatWidget._enhancedMarkdownParser) {
|
|
131
|
-
return global.ChatWidget._enhancedMarkdownParser(text);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Fallback: Simple markdown parsing for common patterns
|
|
135
|
-
let html = escapeHtml(text);
|
|
136
|
-
|
|
137
|
-
// Bold: **text** or __text__
|
|
138
|
-
html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
|
|
139
|
-
html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
|
|
140
|
-
|
|
141
|
-
// Italic: *text* or _text_
|
|
142
|
-
html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
|
|
143
|
-
html = html.replace(/_(.+?)_/g, '<em>$1</em>');
|
|
144
|
-
|
|
145
|
-
// Code: `code`
|
|
146
|
-
html = html.replace(/`(.+?)`/g, '<code>$1</code>');
|
|
147
|
-
|
|
148
|
-
// Links: [text](url)
|
|
149
|
-
html = html.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
|
|
150
|
-
|
|
151
|
-
// Line breaks
|
|
152
|
-
html = html.replace(/\n/g, '<br>');
|
|
153
|
-
|
|
154
|
-
// Lists: - item or * item
|
|
155
|
-
html = html.replace(/^[\-\*]\s+(.+)$/gm, '<li>$1</li>');
|
|
156
|
-
html = html.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
|
|
157
|
-
|
|
158
|
-
return html;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function getStoredValue(key) {
|
|
162
|
-
try {
|
|
163
|
-
return localStorage.getItem(key);
|
|
164
|
-
} catch (e) {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function setStoredValue(key, value) {
|
|
170
|
-
try {
|
|
171
|
-
if (value === null) {
|
|
172
|
-
localStorage.removeItem(key);
|
|
173
|
-
} else {
|
|
174
|
-
localStorage.setItem(key, value);
|
|
175
|
-
}
|
|
176
|
-
} catch (e) {
|
|
177
|
-
// Ignore storage errors
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// ============================================================================
|
|
182
|
-
// Text-to-Speech (ElevenLabs)
|
|
183
|
-
// ============================================================================
|
|
184
|
-
|
|
185
|
-
async function speakText(text, role) {
|
|
186
|
-
if (!config.enableTTS) return;
|
|
187
|
-
|
|
188
|
-
// Check if we have either proxy or direct API access
|
|
189
|
-
if (!config.ttsProxyUrl && !config.elevenLabsApiKey) return;
|
|
190
|
-
|
|
191
|
-
// If using direct API, check for voice ID
|
|
192
|
-
if (!config.ttsProxyUrl) {
|
|
193
|
-
const voiceId = role === 'assistant' ? config.ttsVoices.assistant : config.ttsVoices.user;
|
|
194
|
-
if (!voiceId) return;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Add to queue
|
|
198
|
-
state.speechQueue.push({ text, role });
|
|
199
|
-
|
|
200
|
-
// Process queue if not already speaking
|
|
201
|
-
if (!state.isSpeaking) {
|
|
202
|
-
processSpeechQueue();
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
async function processSpeechQueue() {
|
|
207
|
-
if (state.speechQueue.length === 0) {
|
|
208
|
-
state.isSpeaking = false;
|
|
209
|
-
render();
|
|
210
|
-
|
|
211
|
-
// If auto-run is waiting for speech to finish, continue
|
|
212
|
-
if (state.autoRunActive && state.autoRunPaused && config.autoRunMode === 'automatic') {
|
|
213
|
-
setTimeout(() => {
|
|
214
|
-
if (state.autoRunActive && !state.isSpeaking) {
|
|
215
|
-
continueAutoRun();
|
|
216
|
-
}
|
|
217
|
-
}, config.autoRunDelay);
|
|
218
|
-
}
|
|
219
|
-
return;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
state.isSpeaking = true;
|
|
223
|
-
render();
|
|
224
|
-
|
|
225
|
-
const { text, role } = state.speechQueue.shift();
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
let response;
|
|
229
|
-
|
|
230
|
-
if (config.ttsProxyUrl) {
|
|
231
|
-
// Use Django proxy
|
|
232
|
-
response = await fetch(config.ttsProxyUrl, getFetchOptions({
|
|
233
|
-
method: 'POST',
|
|
234
|
-
headers: {
|
|
235
|
-
'Content-Type': 'application/json',
|
|
236
|
-
},
|
|
237
|
-
body: JSON.stringify({
|
|
238
|
-
text: text,
|
|
239
|
-
role: role,
|
|
240
|
-
}),
|
|
241
|
-
}));
|
|
242
|
-
} else {
|
|
243
|
-
// Direct ElevenLabs API call
|
|
244
|
-
const voiceId = role === 'assistant' ? config.ttsVoices.assistant : config.ttsVoices.user;
|
|
245
|
-
response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voiceId}`, {
|
|
246
|
-
method: 'POST',
|
|
247
|
-
headers: {
|
|
248
|
-
'Accept': 'audio/mpeg',
|
|
249
|
-
'Content-Type': 'application/json',
|
|
250
|
-
'xi-api-key': config.elevenLabsApiKey,
|
|
251
|
-
},
|
|
252
|
-
body: JSON.stringify({
|
|
253
|
-
text: text,
|
|
254
|
-
model_id: config.ttsModel,
|
|
255
|
-
voice_settings: config.ttsSettings,
|
|
256
|
-
}),
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
if (!response.ok) {
|
|
261
|
-
throw new Error(`TTS API error: ${response.status}`);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
const audioBlob = await response.blob();
|
|
265
|
-
const audioUrl = URL.createObjectURL(audioBlob);
|
|
266
|
-
const audio = new Audio(audioUrl);
|
|
267
|
-
|
|
268
|
-
state.currentAudio = audio;
|
|
269
|
-
|
|
270
|
-
audio.onended = () => {
|
|
271
|
-
URL.revokeObjectURL(audioUrl);
|
|
272
|
-
state.currentAudio = null;
|
|
273
|
-
processSpeechQueue();
|
|
274
|
-
};
|
|
275
|
-
|
|
276
|
-
audio.onerror = () => {
|
|
277
|
-
console.error('[ChatWidget] Audio playback error');
|
|
278
|
-
URL.revokeObjectURL(audioUrl);
|
|
279
|
-
state.currentAudio = null;
|
|
280
|
-
processSpeechQueue();
|
|
281
|
-
};
|
|
282
|
-
|
|
283
|
-
await audio.play();
|
|
284
|
-
} catch (err) {
|
|
285
|
-
console.error('[ChatWidget] TTS error:', err);
|
|
286
|
-
state.currentAudio = null;
|
|
287
|
-
processSpeechQueue();
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function stopSpeech() {
|
|
292
|
-
if (state.currentAudio) {
|
|
293
|
-
state.currentAudio.pause();
|
|
294
|
-
state.currentAudio = null;
|
|
295
|
-
}
|
|
296
|
-
state.speechQueue = [];
|
|
297
|
-
state.isSpeaking = false;
|
|
298
|
-
render();
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
function toggleTTS() {
|
|
302
|
-
config.enableTTS = !config.enableTTS;
|
|
303
|
-
if (!config.enableTTS) {
|
|
304
|
-
stopSpeech();
|
|
305
|
-
}
|
|
306
|
-
render();
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function toggleVoiceSettings() {
|
|
310
|
-
state.voiceSettingsOpen = !state.voiceSettingsOpen;
|
|
311
|
-
render();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
async function setVoice(role, voiceId) {
|
|
315
|
-
config.ttsVoices[role] = voiceId;
|
|
316
|
-
|
|
317
|
-
// If using proxy, notify backend of voice change
|
|
318
|
-
if (config.ttsProxyUrl) {
|
|
319
|
-
try {
|
|
320
|
-
await getOrCreateSession();
|
|
321
|
-
|
|
322
|
-
await fetch(`${config.backendUrl}${config.apiPaths.ttsSetVoice}`, getFetchOptions({
|
|
323
|
-
method: 'POST',
|
|
324
|
-
headers: {
|
|
325
|
-
'Content-Type': 'application/json',
|
|
326
|
-
},
|
|
327
|
-
body: JSON.stringify({ role, voice_id: voiceId }),
|
|
328
|
-
}));
|
|
329
|
-
} catch (err) {
|
|
330
|
-
console.error('[ChatWidget] Failed to set voice on backend:', err);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
render();
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
async function fetchAvailableVoices() {
|
|
338
|
-
try {
|
|
339
|
-
let voices = [];
|
|
340
|
-
|
|
341
|
-
if (config.ttsProxyUrl) {
|
|
342
|
-
// Fetch voices from Django backend
|
|
343
|
-
await getOrCreateSession();
|
|
344
|
-
|
|
345
|
-
const response = await fetch(`${config.backendUrl}${config.apiPaths.ttsVoices}`, getFetchOptions());
|
|
346
|
-
|
|
347
|
-
if (response.ok) {
|
|
348
|
-
const data = await response.json();
|
|
349
|
-
voices = data.voices || [];
|
|
350
|
-
}
|
|
351
|
-
} else if (config.elevenLabsApiKey) {
|
|
352
|
-
// Fetch voices directly from ElevenLabs
|
|
353
|
-
const response = await fetch('https://api.elevenlabs.io/v1/voices', {
|
|
354
|
-
headers: {
|
|
355
|
-
'xi-api-key': config.elevenLabsApiKey,
|
|
356
|
-
},
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
if (response.ok) {
|
|
360
|
-
const data = await response.json();
|
|
361
|
-
voices = data.voices || [];
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
config.availableVoices = voices;
|
|
366
|
-
render(); // Re-render to update dropdowns
|
|
367
|
-
} catch (err) {
|
|
368
|
-
console.error('[ChatWidget] Failed to fetch voices:', err);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// ============================================================================
|
|
373
|
-
// Authentication
|
|
374
|
-
// ============================================================================
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Determine the effective auth strategy based on config
|
|
378
|
-
*/
|
|
379
|
-
function getAuthStrategy() {
|
|
380
|
-
if (config.authStrategy) {
|
|
381
|
-
return config.authStrategy;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Auto-detect strategy based on config
|
|
385
|
-
if (config.authToken) {
|
|
386
|
-
return 'token'; // Default to token auth if token provided
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Check for legacy anonymous session config
|
|
390
|
-
if (config.apiPaths.anonymousSession || config.anonymousSessionEndpoint) {
|
|
391
|
-
return 'anonymous';
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return 'none';
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Get auth headers based on current strategy
|
|
399
|
-
*/
|
|
400
|
-
function getAuthHeaders() {
|
|
401
|
-
const strategy = getAuthStrategy();
|
|
402
|
-
const headers = {};
|
|
403
|
-
|
|
404
|
-
switch (strategy) {
|
|
405
|
-
case 'token': {
|
|
406
|
-
const token = config.authToken || state.authToken;
|
|
407
|
-
if (token) {
|
|
408
|
-
const headerName = config.authHeader || 'Authorization';
|
|
409
|
-
const prefix = config.authTokenPrefix !== undefined ? config.authTokenPrefix : 'Token';
|
|
410
|
-
headers[headerName] = prefix ? `${prefix} ${token}` : token;
|
|
411
|
-
}
|
|
412
|
-
break;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
case 'jwt': {
|
|
416
|
-
const token = config.authToken || state.authToken;
|
|
417
|
-
if (token) {
|
|
418
|
-
const headerName = config.authHeader || 'Authorization';
|
|
419
|
-
const prefix = config.authTokenPrefix !== undefined ? config.authTokenPrefix : 'Bearer';
|
|
420
|
-
headers[headerName] = prefix ? `${prefix} ${token}` : token;
|
|
421
|
-
}
|
|
422
|
-
break;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
case 'anonymous': {
|
|
426
|
-
const token = state.authToken || state.sessionToken; // Support legacy sessionToken
|
|
427
|
-
if (token) {
|
|
428
|
-
const headerName = config.authHeader || config.anonymousTokenHeader || 'X-Anonymous-Token';
|
|
429
|
-
headers[headerName] = token;
|
|
430
|
-
}
|
|
431
|
-
break;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
case 'session':
|
|
435
|
-
// Session auth uses cookies, no headers needed
|
|
436
|
-
break;
|
|
437
|
-
|
|
438
|
-
case 'none':
|
|
439
|
-
// No auth
|
|
440
|
-
break;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
return headers;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Get fetch options including auth credentials
|
|
448
|
-
*/
|
|
449
|
-
function getFetchOptions(options = {}) {
|
|
450
|
-
const strategy = getAuthStrategy();
|
|
451
|
-
const fetchOptions = { ...options };
|
|
452
|
-
|
|
453
|
-
// Add auth headers
|
|
454
|
-
fetchOptions.headers = {
|
|
455
|
-
...fetchOptions.headers,
|
|
456
|
-
...getAuthHeaders(),
|
|
457
|
-
};
|
|
458
|
-
|
|
459
|
-
// For session auth, include credentials
|
|
460
|
-
if (strategy === 'session') {
|
|
461
|
-
fetchOptions.credentials = 'include';
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return fetchOptions;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
/**
|
|
468
|
-
* Handle auth errors (401, 403)
|
|
469
|
-
*/
|
|
470
|
-
function handleAuthError(error, response) {
|
|
471
|
-
if (config.onAuthError && typeof config.onAuthError === 'function') {
|
|
472
|
-
const authError = new Error(error.message || 'Authentication failed');
|
|
473
|
-
authError.status = response?.status;
|
|
474
|
-
authError.response = response;
|
|
475
|
-
config.onAuthError(authError);
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// ============================================================================
|
|
480
|
-
// Session Management
|
|
481
|
-
// ============================================================================
|
|
482
|
-
|
|
483
|
-
async function getOrCreateSession() {
|
|
484
|
-
const strategy = getAuthStrategy();
|
|
485
|
-
|
|
486
|
-
// For non-anonymous strategies, return the configured token
|
|
487
|
-
if (strategy !== 'anonymous') {
|
|
488
|
-
return config.authToken || state.authToken;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// Anonymous strategy: get or create anonymous token
|
|
492
|
-
if (state.authToken) {
|
|
493
|
-
return state.authToken;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// Support legacy sessionToken
|
|
497
|
-
if (state.sessionToken) {
|
|
498
|
-
state.authToken = state.sessionToken;
|
|
499
|
-
return state.authToken;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// Try to restore from storage
|
|
503
|
-
const storageKey = config.anonymousTokenKey || config.sessionTokenKey;
|
|
504
|
-
const stored = getStoredValue(storageKey);
|
|
505
|
-
if (stored) {
|
|
506
|
-
state.authToken = stored;
|
|
507
|
-
state.sessionToken = stored; // Keep legacy field in sync
|
|
508
|
-
return stored;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
// Create new anonymous session
|
|
512
|
-
try {
|
|
513
|
-
const endpoint = config.anonymousSessionEndpoint || config.apiPaths.anonymousSession;
|
|
514
|
-
const response = await fetch(`${config.backendUrl}${endpoint}`, {
|
|
515
|
-
method: 'POST',
|
|
516
|
-
headers: { 'Content-Type': 'application/json' },
|
|
517
|
-
});
|
|
518
|
-
|
|
519
|
-
if (response.ok) {
|
|
520
|
-
const data = await response.json();
|
|
521
|
-
const token = data.token;
|
|
522
|
-
state.authToken = token;
|
|
523
|
-
state.sessionToken = token; // Keep legacy field in sync
|
|
524
|
-
setStoredValue(storageKey, token);
|
|
525
|
-
return token;
|
|
526
|
-
} else if (response.status === 401 || response.status === 403) {
|
|
527
|
-
handleAuthError(new Error('Failed to create anonymous session'), response);
|
|
528
|
-
}
|
|
529
|
-
} catch (e) {
|
|
530
|
-
console.warn('[ChatWidget] Failed to create session:', e);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
return null;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
// ============================================================================
|
|
537
|
-
// API Functions
|
|
538
|
-
// ============================================================================
|
|
539
|
-
|
|
540
|
-
async function sendMessage(content) {
|
|
541
|
-
if (!content.trim() || state.isLoading) return;
|
|
542
|
-
|
|
543
|
-
state.isLoading = true;
|
|
544
|
-
state.error = null;
|
|
545
|
-
|
|
546
|
-
// Add user message immediately
|
|
547
|
-
const userMessage = {
|
|
548
|
-
id: generateId(),
|
|
549
|
-
role: 'user',
|
|
550
|
-
content: content.trim(),
|
|
551
|
-
timestamp: new Date(),
|
|
552
|
-
type: 'message',
|
|
553
|
-
};
|
|
554
|
-
state.messages.push(userMessage);
|
|
555
|
-
render();
|
|
556
|
-
|
|
557
|
-
try {
|
|
558
|
-
// Get auth token (if using anonymous strategy)
|
|
559
|
-
const token = await getOrCreateSession();
|
|
560
|
-
|
|
561
|
-
// Restore conversation ID from storage if not set
|
|
562
|
-
if (!state.conversationId) {
|
|
563
|
-
state.conversationId = getStoredValue(config.conversationIdKey);
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
const response = await fetch(`${config.backendUrl}${config.apiPaths.runs}`, getFetchOptions({
|
|
567
|
-
method: 'POST',
|
|
568
|
-
headers: { 'Content-Type': 'application/json' },
|
|
569
|
-
body: JSON.stringify({
|
|
570
|
-
agentKey: config.agentKey,
|
|
571
|
-
conversationId: state.conversationId,
|
|
572
|
-
messages: [{ role: 'user', content: content.trim() }],
|
|
573
|
-
metadata: { journey_type: state.journeyType },
|
|
574
|
-
}),
|
|
575
|
-
}));
|
|
576
|
-
|
|
577
|
-
if (!response.ok) {
|
|
578
|
-
const errorData = await response.json().catch(() => ({}));
|
|
579
|
-
const error = new Error(errorData.error || `HTTP ${response.status}`);
|
|
580
|
-
|
|
581
|
-
// Handle auth errors
|
|
582
|
-
if (response.status === 401 || response.status === 403) {
|
|
583
|
-
handleAuthError(error, response);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
throw error;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
const run = await response.json();
|
|
590
|
-
|
|
591
|
-
// Store conversation ID
|
|
592
|
-
if (!state.conversationId && run.conversationId) {
|
|
593
|
-
state.conversationId = run.conversationId;
|
|
594
|
-
setStoredValue(config.conversationIdKey, run.conversationId);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// Subscribe to SSE events
|
|
598
|
-
await subscribeToEvents(run.id, token);
|
|
599
|
-
|
|
600
|
-
} catch (err) {
|
|
601
|
-
state.error = err.message || 'Failed to send message';
|
|
602
|
-
state.isLoading = false;
|
|
603
|
-
render();
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
async function subscribeToEvents(runId, token) {
|
|
608
|
-
// Close existing connection
|
|
609
|
-
if (state.eventSource) {
|
|
610
|
-
state.eventSource.close();
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
const eventPath = config.apiPaths.runEvents.replace('{runId}', runId);
|
|
614
|
-
let url = `${config.backendUrl}${eventPath}`;
|
|
615
|
-
if (token) {
|
|
616
|
-
url += `?anonymous_token=${encodeURIComponent(token)}`;
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
const eventSource = new EventSource(url);
|
|
620
|
-
state.eventSource = eventSource;
|
|
621
|
-
|
|
622
|
-
let assistantContent = '';
|
|
623
|
-
|
|
624
|
-
// Handler for assistant messages
|
|
625
|
-
eventSource.addEventListener('assistant.message', (event) => {
|
|
626
|
-
try {
|
|
627
|
-
const data = JSON.parse(event.data);
|
|
628
|
-
|
|
629
|
-
// Call onEvent callback if provided
|
|
630
|
-
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
631
|
-
config.onEvent('assistant.message', data.payload);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
const content = data.payload.content;
|
|
635
|
-
if (content) {
|
|
636
|
-
assistantContent += content;
|
|
637
|
-
|
|
638
|
-
// Update or add assistant message
|
|
639
|
-
const lastMsg = state.messages[state.messages.length - 1];
|
|
640
|
-
if (lastMsg?.role === 'assistant' && lastMsg.id.startsWith('assistant-stream-')) {
|
|
641
|
-
lastMsg.content = assistantContent;
|
|
642
|
-
} else {
|
|
643
|
-
state.messages.push({
|
|
644
|
-
id: 'assistant-stream-' + Date.now(),
|
|
645
|
-
role: 'assistant',
|
|
646
|
-
content: assistantContent,
|
|
647
|
-
timestamp: new Date(),
|
|
648
|
-
type: 'message',
|
|
649
|
-
});
|
|
650
|
-
}
|
|
651
|
-
render();
|
|
652
|
-
}
|
|
653
|
-
} catch (err) {
|
|
654
|
-
console.error('[ChatWidget] Failed to parse assistant.message:', err);
|
|
655
|
-
}
|
|
656
|
-
});
|
|
657
|
-
|
|
658
|
-
// Handler for tool calls (debug mode)
|
|
659
|
-
eventSource.addEventListener('tool.call', (event) => {
|
|
660
|
-
try {
|
|
661
|
-
const data = JSON.parse(event.data);
|
|
662
|
-
|
|
663
|
-
// Call onEvent callback if provided
|
|
664
|
-
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
665
|
-
config.onEvent('tool.call', data.payload);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
if (state.debugMode) {
|
|
669
|
-
state.messages.push({
|
|
670
|
-
id: 'tool-call-' + Date.now(),
|
|
671
|
-
role: 'system',
|
|
672
|
-
content: `🔧 Tool: ${data.payload.name}`,
|
|
673
|
-
timestamp: new Date(),
|
|
674
|
-
type: 'tool_call',
|
|
675
|
-
metadata: { name: data.payload.name, arguments: data.payload.arguments },
|
|
676
|
-
});
|
|
677
|
-
render();
|
|
678
|
-
}
|
|
679
|
-
} catch (err) {
|
|
680
|
-
console.error('[ChatWidget] Failed to parse tool.call:', err);
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
|
|
684
|
-
// Handler for tool results (debug mode)
|
|
685
|
-
eventSource.addEventListener('tool.result', (event) => {
|
|
686
|
-
try {
|
|
687
|
-
const data = JSON.parse(event.data);
|
|
688
|
-
|
|
689
|
-
// Call onEvent callback if provided
|
|
690
|
-
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
691
|
-
config.onEvent('tool.result', data.payload);
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
if (state.debugMode) {
|
|
695
|
-
const result = data.payload.result || '';
|
|
696
|
-
state.messages.push({
|
|
697
|
-
id: 'tool-result-' + Date.now(),
|
|
698
|
-
role: 'system',
|
|
699
|
-
content: `✅ Result: ${result.substring(0, 100)}${result.length > 100 ? '...' : ''}`,
|
|
700
|
-
timestamp: new Date(),
|
|
701
|
-
type: 'tool_result',
|
|
702
|
-
metadata: { result },
|
|
703
|
-
});
|
|
704
|
-
render();
|
|
705
|
-
}
|
|
706
|
-
} catch (err) {
|
|
707
|
-
console.error('[ChatWidget] Failed to parse tool.result:', err);
|
|
708
|
-
}
|
|
709
|
-
});
|
|
710
|
-
|
|
711
|
-
// Terminal event handlers
|
|
712
|
-
const handleTerminal = (event) => {
|
|
713
|
-
try {
|
|
714
|
-
const data = JSON.parse(event.data);
|
|
715
|
-
|
|
716
|
-
// Call onEvent callback if provided
|
|
717
|
-
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
718
|
-
config.onEvent(data.type, data.payload);
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
if (data.type === 'run.failed') {
|
|
722
|
-
state.error = data.payload.error || 'Agent run failed';
|
|
723
|
-
state.messages.push({
|
|
724
|
-
id: 'error-' + Date.now(),
|
|
725
|
-
role: 'system',
|
|
726
|
-
content: `❌ Error: ${state.error}`,
|
|
727
|
-
timestamp: new Date(),
|
|
728
|
-
type: 'error',
|
|
729
|
-
});
|
|
730
|
-
}
|
|
731
|
-
} catch (err) {
|
|
732
|
-
console.error('[ChatWidget] Failed to parse terminal event:', err);
|
|
733
|
-
}
|
|
734
|
-
state.isLoading = false;
|
|
735
|
-
eventSource.close();
|
|
736
|
-
state.eventSource = null;
|
|
737
|
-
render();
|
|
738
|
-
|
|
739
|
-
// Speak assistant message if TTS enabled
|
|
740
|
-
if (assistantContent && !state.error) {
|
|
741
|
-
speakText(assistantContent, 'assistant');
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
// Trigger auto-run if enabled
|
|
745
|
-
if (state.autoRunActive && !state.error) {
|
|
746
|
-
if (config.autoRunMode === 'automatic') {
|
|
747
|
-
// Wait for speech to finish before continuing
|
|
748
|
-
if (config.enableTTS && assistantContent) {
|
|
749
|
-
state.autoRunPaused = true;
|
|
750
|
-
// processSpeechQueue will continue when done
|
|
751
|
-
} else {
|
|
752
|
-
setTimeout(() => triggerAutoRun(), config.autoRunDelay);
|
|
753
|
-
}
|
|
754
|
-
} else if (config.autoRunMode === 'confirm') {
|
|
755
|
-
state.autoRunPaused = true;
|
|
756
|
-
render();
|
|
757
|
-
}
|
|
758
|
-
}
|
|
759
|
-
};
|
|
760
|
-
|
|
761
|
-
eventSource.addEventListener('run.succeeded', handleTerminal);
|
|
762
|
-
eventSource.addEventListener('run.failed', handleTerminal);
|
|
763
|
-
eventSource.addEventListener('run.cancelled', handleTerminal);
|
|
764
|
-
eventSource.addEventListener('run.timed_out', handleTerminal);
|
|
765
|
-
|
|
766
|
-
// Generic handler for any other custom events
|
|
767
|
-
eventSource.onmessage = (event) => {
|
|
768
|
-
try {
|
|
769
|
-
const data = JSON.parse(event.data);
|
|
770
|
-
|
|
771
|
-
// Call onEvent callback for any unhandled events
|
|
772
|
-
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
773
|
-
// Extract event type from data or use 'message' as default
|
|
774
|
-
const eventType = data.type || 'message';
|
|
775
|
-
config.onEvent(eventType, data.payload || data);
|
|
776
|
-
}
|
|
777
|
-
} catch (err) {
|
|
778
|
-
console.debug('[ChatWidget] Received non-JSON SSE message:', event.data);
|
|
779
|
-
}
|
|
780
|
-
};
|
|
781
|
-
|
|
782
|
-
eventSource.onerror = () => {
|
|
783
|
-
if (eventSource.readyState !== EventSource.CLOSED) {
|
|
784
|
-
console.debug('[ChatWidget] SSE connection closed');
|
|
785
|
-
}
|
|
786
|
-
state.isLoading = false;
|
|
787
|
-
eventSource.close();
|
|
788
|
-
state.eventSource = null;
|
|
789
|
-
render();
|
|
790
|
-
};
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
// ============================================================================
|
|
794
|
-
// Auto-Run / Demo Mode
|
|
795
|
-
// ============================================================================
|
|
796
|
-
|
|
797
|
-
async function triggerAutoRun() {
|
|
798
|
-
if (!state.autoRunActive || state.isLoading || state.isSimulating) return;
|
|
799
|
-
|
|
800
|
-
const lastMessage = state.messages[state.messages.length - 1];
|
|
801
|
-
if (lastMessage?.role !== 'assistant') return;
|
|
802
|
-
|
|
803
|
-
state.isSimulating = true;
|
|
804
|
-
state.autoRunPaused = false;
|
|
805
|
-
render();
|
|
806
|
-
|
|
807
|
-
try {
|
|
808
|
-
const response = await fetch(`${config.backendUrl}${config.apiPaths.simulateCustomer}`, {
|
|
809
|
-
method: 'POST',
|
|
810
|
-
headers: { 'Content-Type': 'application/json' },
|
|
811
|
-
body: JSON.stringify({
|
|
812
|
-
messages: state.messages.map(m => ({ role: m.role, content: m.content })),
|
|
813
|
-
journey_type: state.journeyType,
|
|
814
|
-
}),
|
|
815
|
-
});
|
|
816
|
-
|
|
817
|
-
if (response.ok) {
|
|
818
|
-
const data = await response.json();
|
|
819
|
-
if (data.response) {
|
|
820
|
-
state.isSimulating = false;
|
|
821
|
-
|
|
822
|
-
// Speak simulated user message if TTS enabled
|
|
823
|
-
if (config.enableTTS) {
|
|
824
|
-
await speakText(data.response, 'user');
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
await sendMessage(data.response);
|
|
828
|
-
return;
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
} catch (err) {
|
|
832
|
-
console.error('[ChatWidget] Failed to simulate customer:', err);
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
state.isSimulating = false;
|
|
836
|
-
render();
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
async function startDemoFlow(journeyType) {
|
|
840
|
-
clearMessages();
|
|
841
|
-
state.journeyType = journeyType;
|
|
842
|
-
state.autoRunActive = true;
|
|
843
|
-
state.autoRunPaused = false;
|
|
844
|
-
render();
|
|
845
|
-
|
|
846
|
-
const journey = config.journeyTypes[journeyType];
|
|
847
|
-
if (journey?.initialMessage) {
|
|
848
|
-
setTimeout(async () => {
|
|
849
|
-
state.isSimulating = true;
|
|
850
|
-
render();
|
|
851
|
-
|
|
852
|
-
// Speak initial message if TTS enabled
|
|
853
|
-
if (config.enableTTS) {
|
|
854
|
-
await speakText(journey.initialMessage, 'user');
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
sendMessage(journey.initialMessage).then(() => {
|
|
858
|
-
state.isSimulating = false;
|
|
859
|
-
render();
|
|
860
|
-
});
|
|
861
|
-
}, 100);
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
|
|
865
|
-
function stopAutoRun() {
|
|
866
|
-
state.autoRunActive = false;
|
|
867
|
-
state.autoRunPaused = false;
|
|
868
|
-
render();
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
function continueAutoRun() {
|
|
872
|
-
if (state.autoRunActive && state.autoRunPaused) {
|
|
873
|
-
triggerAutoRun();
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
function setAutoRunMode(mode) {
|
|
878
|
-
if (['automatic', 'confirm', 'manual'].includes(mode)) {
|
|
879
|
-
config.autoRunMode = mode;
|
|
880
|
-
render();
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
function setAutoRunDelay(delay) {
|
|
885
|
-
config.autoRunDelay = Math.max(0, parseInt(delay) || 1000);
|
|
886
|
-
render();
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
// ============================================================================
|
|
890
|
-
// UI Actions
|
|
891
|
-
// ============================================================================
|
|
892
|
-
|
|
893
|
-
function openWidget() {
|
|
894
|
-
state.isOpen = true;
|
|
895
|
-
getOrCreateSession();
|
|
896
|
-
render();
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
function closeWidget() {
|
|
900
|
-
state.isOpen = false;
|
|
901
|
-
state.autoRunActive = false;
|
|
902
|
-
state.autoRunPaused = false;
|
|
903
|
-
render();
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
function toggleExpand() {
|
|
907
|
-
state.isExpanded = !state.isExpanded;
|
|
908
|
-
render();
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
function toggleDebugMode() {
|
|
912
|
-
state.debugMode = !state.debugMode;
|
|
913
|
-
render();
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
function clearMessages() {
|
|
917
|
-
state.messages = [];
|
|
918
|
-
state.conversationId = null;
|
|
919
|
-
state.error = null;
|
|
920
|
-
state.autoRunActive = false;
|
|
921
|
-
state.autoRunPaused = false;
|
|
922
|
-
setStoredValue(config.conversationIdKey, null);
|
|
923
|
-
render();
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
// ============================================================================
|
|
927
|
-
// Render Functions
|
|
928
|
-
// ============================================================================
|
|
929
|
-
|
|
930
|
-
function renderMessage(msg) {
|
|
931
|
-
const isUser = msg.role === 'user';
|
|
932
|
-
const isToolCall = msg.type === 'tool_call';
|
|
933
|
-
const isToolResult = msg.type === 'tool_result';
|
|
934
|
-
const isError = msg.type === 'error';
|
|
935
|
-
|
|
936
|
-
// Hide debug messages if debug mode is off
|
|
937
|
-
if ((isToolCall || isToolResult) && !state.debugMode) {
|
|
938
|
-
return '';
|
|
939
|
-
}
|
|
940
|
-
|
|
941
|
-
let classes = 'cw-message';
|
|
942
|
-
if (isUser) classes += ' cw-message-user';
|
|
943
|
-
if (isToolCall) classes += ' cw-message-tool-call';
|
|
944
|
-
if (isToolResult) classes += ' cw-message-tool-result';
|
|
945
|
-
if (isError) classes += ' cw-message-error';
|
|
946
|
-
|
|
947
|
-
let content = msg.role === 'assistant' ? parseMarkdown(msg.content) : escapeHtml(msg.content);
|
|
948
|
-
|
|
949
|
-
// Add tool arguments for tool calls
|
|
950
|
-
if (isToolCall && msg.metadata?.arguments) {
|
|
951
|
-
content += `<pre class="cw-tool-args">${escapeHtml(JSON.stringify(msg.metadata.arguments, null, 2))}</pre>`;
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
return `
|
|
955
|
-
<div class="cw-message-row ${isUser ? 'cw-message-row-user' : ''}">
|
|
956
|
-
<div class="${classes}">${content}</div>
|
|
1
|
+
var ChatWidgetModule=(()=>{var he=Object.defineProperty;var wt=Object.getOwnPropertyDescriptor;var $t=Object.getOwnPropertyNames;var bt=Object.prototype.hasOwnProperty;var kt=(e,t)=>{for(var n in t)he(e,n,{get:t[n],enumerable:!0})},Ct=(e,t,n,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let a of $t(t))!bt.call(e,a)&&a!==n&&he(e,a,{get:()=>t[a],enumerable:!(s=wt(t,a))||s.enumerable});return e};var St=e=>Ct(he({},"__esModule",{value:!0}),e);var Xt={};kt(Xt,{ChatWidget:()=>fe,default:()=>Gt});var re,M,De,Tt,G,xe,He,Ae,Ne,ve,me,ye,Mt,Z={},Oe=[],xt=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,le=Array.isArray;function q(e,t){for(var n in t)e[n]=t[n];return e}function we(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function ie(e,t,n){var s,a,o,l={};for(o in t)o=="key"?s=t[o]:o=="ref"?a=t[o]:l[o]=t[o];if(arguments.length>2&&(l.children=arguments.length>3?re.call(arguments,2):n),typeof e=="function"&&e.defaultProps!=null)for(o in e.defaultProps)l[o]===void 0&&(l[o]=e.defaultProps[o]);return se(e,l,s,a,null)}function se(e,t,n,s,a){var o={type:e,props:t,key:n,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:a??++De,__i:-1,__u:0};return a==null&&M.vnode!=null&&M.vnode(o),o}function ce(e){return e.children}function Y(e,t){this.props=e,this.context=t}function X(e,t){if(t==null)return e.__?X(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if((n=e.__k[t])!=null&&n.__e!=null)return n.__e;return typeof e.type=="function"?X(e):null}function Re(e){var t,n;if((e=e.__)!=null&&e.__c!=null){for(e.__e=e.__c.base=null,t=0;t<e.__k.length;t++)if((n=e.__k[t])!=null&&n.__e!=null){e.__e=e.__c.base=n.__e;break}return Re(e)}}function Ee(e){(!e.__d&&(e.__d=!0)&&G.push(e)&&!ae.__r++||xe!=M.debounceRendering)&&((xe=M.debounceRendering)||He)(ae)}function ae(){for(var e,t,n,s,a,o,l,c=1;G.length;)G.length>c&&G.sort(Ae),e=G.shift(),c=G.length,e.__d&&(n=void 0,s=void 0,a=(s=(t=e).__v).__e,o=[],l=[],t.__P&&((n=q({},s)).__v=s.__v+1,M.vnode&&M.vnode(n),$e(t.__P,n,s,t.__n,t.__P.namespaceURI,32&s.__u?[a]:null,o,a??X(s),!!(32&s.__u),l),n.__v=s.__v,n.__.__k[n.__i]=n,Le(o,n,l),s.__e=s.__=null,n.__e!=a&&Re(n)));ae.__r=0}function Ue(e,t,n,s,a,o,l,c,_,i,u){var r,f,d,m,S,b,g,w=s&&s.__k||Oe,N=t.length;for(_=Et(n,t,w,_,N),r=0;r<N;r++)(d=n.__k[r])!=null&&(f=d.__i==-1?Z:w[d.__i]||Z,d.__i=r,b=$e(e,d,f,a,o,l,c,_,i,u),m=d.__e,d.ref&&f.ref!=d.ref&&(f.ref&&be(f.ref,null,d),u.push(d.ref,d.__c||m,d)),S==null&&m!=null&&(S=m),(g=!!(4&d.__u))||f.__k===d.__k?_=Fe(d,_,e,g):typeof d.type=="function"&&b!==void 0?_=b:m&&(_=m.nextSibling),d.__u&=-7);return n.__e=S,_}function Et(e,t,n,s,a){var o,l,c,_,i,u=n.length,r=u,f=0;for(e.__k=new Array(a),o=0;o<a;o++)(l=t[o])!=null&&typeof l!="boolean"&&typeof l!="function"?(typeof l=="string"||typeof l=="number"||typeof l=="bigint"||l.constructor==String?l=e.__k[o]=se(null,l,null,null,null):le(l)?l=e.__k[o]=se(ce,{children:l},null,null,null):l.constructor===void 0&&l.__b>0?l=e.__k[o]=se(l.type,l.props,l.key,l.ref?l.ref:null,l.__v):e.__k[o]=l,_=o+f,l.__=e,l.__b=e.__b+1,c=null,(i=l.__i=It(l,n,_,r))!=-1&&(r--,(c=n[i])&&(c.__u|=2)),c==null||c.__v==null?(i==-1&&(a>u?f--:a<u&&f++),typeof l.type!="function"&&(l.__u|=4)):i!=_&&(i==_-1?f--:i==_+1?f++:(i>_?f--:f++,l.__u|=4))):e.__k[o]=null;if(r)for(o=0;o<u;o++)(c=n[o])!=null&&!(2&c.__u)&&(c.__e==s&&(s=X(c)),Ke(c,c));return s}function Fe(e,t,n,s){var a,o;if(typeof e.type=="function"){for(a=e.__k,o=0;a&&o<a.length;o++)a[o]&&(a[o].__=e,t=Fe(a[o],t,n,s));return t}e.__e!=t&&(s&&(t&&e.type&&!t.parentNode&&(t=X(e)),n.insertBefore(e.__e,t||null)),t=e.__e);do t=t&&t.nextSibling;while(t!=null&&t.nodeType==8);return t}function It(e,t,n,s){var a,o,l,c=e.key,_=e.type,i=t[n],u=i!=null&&(2&i.__u)==0;if(i===null&&c==null||u&&c==i.key&&_==i.type)return n;if(s>(u?1:0)){for(a=n-1,o=n+1;a>=0||o<t.length;)if((i=t[l=a>=0?a--:o++])!=null&&!(2&i.__u)&&c==i.key&&_==i.type)return l}return-1}function Ie(e,t,n){t[0]=="-"?e.setProperty(t,n??""):e[t]=n==null?"":typeof n!="number"||xt.test(t)?n:n+"px"}function oe(e,t,n,s,a){var o,l;e:if(t=="style")if(typeof n=="string")e.style.cssText=n;else{if(typeof s=="string"&&(e.style.cssText=s=""),s)for(t in s)n&&t in n||Ie(e.style,t,"");if(n)for(t in n)s&&n[t]==s[t]||Ie(e.style,t,n[t])}else if(t[0]=="o"&&t[1]=="n")o=t!=(t=t.replace(Ne,"$1")),l=t.toLowerCase(),t=l in e||t=="onFocusOut"||t=="onFocusIn"?l.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+o]=n,n?s?n.u=s.u:(n.u=ve,e.addEventListener(t,o?ye:me,o)):e.removeEventListener(t,o?ye:me,o);else{if(a=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=n??"";break e}catch{}typeof n=="function"||(n==null||n===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&n==1?"":n))}}function Pe(e){return function(t){if(this.l){var n=this.l[t.type+e];if(t.t==null)t.t=ve++;else if(t.t<n.u)return;return n(M.event?M.event(t):t)}}}function $e(e,t,n,s,a,o,l,c,_,i){var u,r,f,d,m,S,b,g,w,N,A,j,O,L,W,F,p,$=t.type;if(t.constructor!==void 0)return null;128&n.__u&&(_=!!(32&n.__u),o=[c=t.__e=n.__e]),(u=M.__b)&&u(t);e:if(typeof $=="function")try{if(g=t.props,w="prototype"in $&&$.prototype.render,N=(u=$.contextType)&&s[u.__c],A=u?N?N.props.value:u.__:s,n.__c?b=(r=t.__c=n.__c).__=r.__E:(w?t.__c=r=new $(g,A):(t.__c=r=new Y(g,A),r.constructor=$,r.render=Dt),N&&N.sub(r),r.state||(r.state={}),r.__n=s,f=r.__d=!0,r.__h=[],r._sb=[]),w&&r.__s==null&&(r.__s=r.state),w&&$.getDerivedStateFromProps!=null&&(r.__s==r.state&&(r.__s=q({},r.__s)),q(r.__s,$.getDerivedStateFromProps(g,r.__s))),d=r.props,m=r.state,r.__v=t,f)w&&$.getDerivedStateFromProps==null&&r.componentWillMount!=null&&r.componentWillMount(),w&&r.componentDidMount!=null&&r.__h.push(r.componentDidMount);else{if(w&&$.getDerivedStateFromProps==null&&g!==d&&r.componentWillReceiveProps!=null&&r.componentWillReceiveProps(g,A),t.__v==n.__v||!r.__e&&r.shouldComponentUpdate!=null&&r.shouldComponentUpdate(g,r.__s,A)===!1){for(t.__v!=n.__v&&(r.props=g,r.state=r.__s,r.__d=!1),t.__e=n.__e,t.__k=n.__k,t.__k.some(function(E){E&&(E.__=t)}),j=0;j<r._sb.length;j++)r.__h.push(r._sb[j]);r._sb=[],r.__h.length&&l.push(r);break e}r.componentWillUpdate!=null&&r.componentWillUpdate(g,r.__s,A),w&&r.componentDidUpdate!=null&&r.__h.push(function(){r.componentDidUpdate(d,m,S)})}if(r.context=A,r.props=g,r.__P=e,r.__e=!1,O=M.__r,L=0,w){for(r.state=r.__s,r.__d=!1,O&&O(t),u=r.render(r.props,r.state,r.context),W=0;W<r._sb.length;W++)r.__h.push(r._sb[W]);r._sb=[]}else do r.__d=!1,O&&O(t),u=r.render(r.props,r.state,r.context),r.state=r.__s;while(r.__d&&++L<25);r.state=r.__s,r.getChildContext!=null&&(s=q(q({},s),r.getChildContext())),w&&!f&&r.getSnapshotBeforeUpdate!=null&&(S=r.getSnapshotBeforeUpdate(d,m)),F=u,u!=null&&u.type===ce&&u.key==null&&(F=We(u.props.children)),c=Ue(e,le(F)?F:[F],t,n,s,a,o,l,c,_,i),r.base=t.__e,t.__u&=-161,r.__h.length&&l.push(r),b&&(r.__E=r.__=null)}catch(E){if(t.__v=null,_||o!=null)if(E.then){for(t.__u|=_?160:128;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;o[o.indexOf(c)]=null,t.__e=c}else{for(p=o.length;p--;)we(o[p]);ge(t)}else t.__e=n.__e,t.__k=n.__k,E.then||ge(t);M.__e(E,t,n)}else o==null&&t.__v==n.__v?(t.__k=n.__k,t.__e=n.__e):c=t.__e=Pt(n.__e,t,n,s,a,o,l,_,i);return(u=M.diffed)&&u(t),128&t.__u?void 0:c}function ge(e){e&&e.__c&&(e.__c.__e=!0),e&&e.__k&&e.__k.forEach(ge)}function Le(e,t,n){for(var s=0;s<n.length;s++)be(n[s],n[++s],n[++s]);M.__c&&M.__c(t,e),e.some(function(a){try{e=a.__h,a.__h=[],e.some(function(o){o.call(a)})}catch(o){M.__e(o,a.__v)}})}function We(e){return typeof e!="object"||e==null||e.__b&&e.__b>0?e:le(e)?e.map(We):q({},e)}function Pt(e,t,n,s,a,o,l,c,_){var i,u,r,f,d,m,S,b=n.props||Z,g=t.props,w=t.type;if(w=="svg"?a="http://www.w3.org/2000/svg":w=="math"?a="http://www.w3.org/1998/Math/MathML":a||(a="http://www.w3.org/1999/xhtml"),o!=null){for(i=0;i<o.length;i++)if((d=o[i])&&"setAttribute"in d==!!w&&(w?d.localName==w:d.nodeType==3)){e=d,o[i]=null;break}}if(e==null){if(w==null)return document.createTextNode(g);e=document.createElementNS(a,w,g.is&&g),c&&(M.__m&&M.__m(t,o),c=!1),o=null}if(w==null)b===g||c&&e.data==g||(e.data=g);else{if(o=o&&re.call(e.childNodes),!c&&o!=null)for(b={},i=0;i<e.attributes.length;i++)b[(d=e.attributes[i]).name]=d.value;for(i in b)if(d=b[i],i!="children"){if(i=="dangerouslySetInnerHTML")r=d;else if(!(i in g)){if(i=="value"&&"defaultValue"in g||i=="checked"&&"defaultChecked"in g)continue;oe(e,i,null,d,a)}}for(i in g)d=g[i],i=="children"?f=d:i=="dangerouslySetInnerHTML"?u=d:i=="value"?m=d:i=="checked"?S=d:c&&typeof d!="function"||b[i]===d||oe(e,i,d,b[i],a);if(u)c||r&&(u.__html==r.__html||u.__html==e.innerHTML)||(e.innerHTML=u.__html),t.__k=[];else if(r&&(e.innerHTML=""),Ue(t.type=="template"?e.content:e,le(f)?f:[f],t,n,s,w=="foreignObject"?"http://www.w3.org/1999/xhtml":a,o,l,o?o[0]:n.__k&&X(n,0),c,_),o!=null)for(i=o.length;i--;)we(o[i]);c||(i="value",w=="progress"&&m==null?e.removeAttribute("value"):m!=null&&(m!==e[i]||w=="progress"&&!m||w=="option"&&m!=b[i])&&oe(e,i,m,b[i],a),i="checked",S!=null&&S!=e[i]&&oe(e,i,S,b[i],a))}return e}function be(e,t,n){try{if(typeof e=="function"){var s=typeof e.__u=="function";s&&e.__u(),s&&t==null||(e.__u=e(t))}else e.current=t}catch(a){M.__e(a,n)}}function Ke(e,t,n){var s,a;if(M.unmount&&M.unmount(e),(s=e.ref)&&(s.current&&s.current!=e.__e||be(s,null,t)),(s=e.__c)!=null){if(s.componentWillUnmount)try{s.componentWillUnmount()}catch(o){M.__e(o,t)}s.base=s.__P=null}if(s=e.__k)for(a=0;a<s.length;a++)s[a]&&Ke(s[a],t,n||typeof e.type!="function");n||we(e.__e),e.__c=e.__=e.__e=void 0}function Dt(e,t,n){return this.constructor(e,n)}function ue(e,t,n){var s,a,o,l;t==document&&(t=document.documentElement),M.__&&M.__(e,t),a=(s=typeof n=="function")?null:n&&n.__k||t.__k,o=[],l=[],$e(t,e=(!s&&n||t).__k=ie(ce,null,[e]),a||Z,Z,t.namespaceURI,!s&&n?[n]:a?null:t.firstChild?re.call(t.childNodes):null,o,!s&&n?n:a?a.__e:t.firstChild,s,l),Le(o,e,l)}re=Oe.slice,M={__e:function(e,t,n,s){for(var a,o,l;t=t.__;)if((a=t.__c)&&!a.__)try{if((o=a.constructor)&&o.getDerivedStateFromError!=null&&(a.setState(o.getDerivedStateFromError(e)),l=a.__d),a.componentDidCatch!=null&&(a.componentDidCatch(e,s||{}),l=a.__d),l)return a.__E=a}catch(c){e=c}throw e}},De=0,Tt=function(e){return e!=null&&e.constructor===void 0},Y.prototype.setState=function(e,t){var n;n=this.__s!=null&&this.__s!=this.state?this.__s:this.__s=q({},this.state),typeof e=="function"&&(e=e(q({},n),this.props)),e&&q(n,e),e!=null&&this.__v&&(t&&this._sb.push(t),Ee(this))},Y.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),Ee(this))},Y.prototype.render=ce,G=[],He=typeof Promise=="function"?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Ae=function(e,t){return e.__v.__b-t.__v.__b},ae.__r=0,Ne=/(PointerCapture)$|Capture$/i,ve=0,me=Pe(!1),ye=Pe(!0),Mt=0;var je=function(e,t,n,s){var a;t[0]=0;for(var o=1;o<t.length;o++){var l=t[o++],c=t[o]?(t[0]|=l?1:2,n[t[o++]]):t[++o];l===3?s[0]=c:l===4?s[1]=Object.assign(s[1]||{},c):l===5?(s[1]=s[1]||{})[t[++o]]=c:l===6?s[1][t[++o]]+=c+"":l?(a=e.apply(c,je(e,c,n,["",null])),s.push(a),c[0]?t[0]|=2:(t[o-2]=0,t[o]=a)):s.push(c)}return s},Be=new Map;function Je(e){var t=Be.get(this);return t||(t=new Map,Be.set(this,t)),(t=je(this,t.get(e)||(t.set(e,t=function(n){for(var s,a,o=1,l="",c="",_=[0],i=function(f){o===1&&(f||(l=l.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?_.push(0,f,l):o===3&&(f||l)?(_.push(3,f,l),o=2):o===2&&l==="..."&&f?_.push(4,f,0):o===2&&l&&!f?_.push(5,0,!0,l):o>=5&&((l||!f&&o===5)&&(_.push(o,0,l,a),o=6),f&&(_.push(o,f,0,a),o=6)),l=""},u=0;u<n.length;u++){u&&(o===1&&i(),i(u));for(var r=0;r<n[u].length;r++)s=n[u][r],o===1?s==="<"?(i(),_=[_],o=3):l+=s:o===4?l==="--"&&s===">"?(o=1,l=""):l=s+l[0]:c?s===c?c="":l+=s:s==='"'||s==="'"?c=s:s===">"?(i(),o=1):o&&(s==="="?(o=5,a=l,l=""):s==="/"&&(o<5||n[u][r+1]===">")?(i(),o===3&&(_=_[0]),o=_,(_=_[0]).push(2,0,o),o=0):s===" "||s===" "||s===`
|
|
2
|
+
`||s==="\r"?(i(),o=2):l+=s),o===3&&l==="!--"&&(o=4,_=_[0])}return i(),_}(e)),t),arguments,[])).length>1?t:t[0]}var y=Je.bind(ie);var ee,P,ke,Ve,te=0,et=[],D=M,qe=D.__b,ze=D.__r,Ge=D.diffed,Xe=D.__c,Qe=D.unmount,Ye=D.__;function Se(e,t){D.__h&&D.__h(P,e,te||t),te=0;var n=P.__H||(P.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function C(e){return te=1,Ht(nt,e)}function Ht(e,t,n){var s=Se(ee++,2);if(s.t=e,!s.__c&&(s.__=[n?n(t):nt(void 0,t),function(c){var _=s.__N?s.__N[0]:s.__[0],i=s.t(_,c);_!==i&&(s.__N=[i,s.__[1]],s.__c.setState({}))}],s.__c=P,!P.__f)){var a=function(c,_,i){if(!s.__c.__H)return!0;var u=s.__c.__H.__.filter(function(f){return!!f.__c});if(u.every(function(f){return!f.__N}))return!o||o.call(this,c,_,i);var r=s.__c.props!==c;return u.forEach(function(f){if(f.__N){var d=f.__[0];f.__=f.__N,f.__N=void 0,d!==f.__[0]&&(r=!0)}}),o&&o.call(this,c,_,i)||r};P.__f=!0;var o=P.shouldComponentUpdate,l=P.componentWillUpdate;P.componentWillUpdate=function(c,_,i){if(this.__e){var u=o;o=void 0,a(c,_,i),o=u}l&&l.call(this,c,_,i)},P.shouldComponentUpdate=a}return s.__N||s.__}function R(e,t){var n=Se(ee++,3);!D.__s&&tt(n.__H,t)&&(n.__=e,n.u=t,P.__H.__h.push(n))}function z(e){return te=5,ne(function(){return{current:e}},[])}function ne(e,t){var n=Se(ee++,7);return tt(n.__H,t)&&(n.__=e(),n.__H=t,n.__h=e),n.__}function U(e,t){return te=8,ne(function(){return e},t)}function At(){for(var e;e=et.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(_e),e.__H.__h.forEach(Ce),e.__H.__h=[]}catch(t){e.__H.__h=[],D.__e(t,e.__v)}}D.__b=function(e){P=null,qe&&qe(e)},D.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),Ye&&Ye(e,t)},D.__r=function(e){ze&&ze(e),ee=0;var t=(P=e.__c).__H;t&&(ke===P?(t.__h=[],P.__h=[],t.__.forEach(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(t.__h.forEach(_e),t.__h.forEach(Ce),t.__h=[],ee=0)),ke=P},D.diffed=function(e){Ge&&Ge(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(et.push(t)!==1&&Ve===D.requestAnimationFrame||((Ve=D.requestAnimationFrame)||Nt)(At)),t.__H.__.forEach(function(n){n.u&&(n.__H=n.u),n.u=void 0})),ke=P=null},D.__c=function(e,t){t.some(function(n){try{n.__h.forEach(_e),n.__h=n.__h.filter(function(s){return!s.__||Ce(s)})}catch(s){t.some(function(a){a.__h&&(a.__h=[])}),t=[],D.__e(s,n.__v)}}),Xe&&Xe(e,t)},D.unmount=function(e){Qe&&Qe(e);var t,n=e.__c;n&&n.__H&&(n.__H.__.forEach(function(s){try{_e(s)}catch(a){t=a}}),n.__H=void 0,t&&D.__e(t,n.__v))};var Ze=typeof requestAnimationFrame=="function";function Nt(e){var t,n=function(){clearTimeout(s),Ze&&cancelAnimationFrame(t),setTimeout(e)},s=setTimeout(n,35);Ze&&(t=requestAnimationFrame(n))}function _e(e){var t=P,n=e.__c;typeof n=="function"&&(e.__c=void 0,n()),P=t}function Ce(e){var t=P;e.__c=e.__(),P=t}function tt(e,t){return!e||e.length!==t.length||t.some(function(n,s){return n!==e[s]})}function nt(e,t){return typeof t=="function"?t(e):t}function de(){return"msg-"+Date.now()+"-"+Math.random().toString(36).substr(2,9)}function H(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}function ot(e){if(!e)return"";try{let t=new Date(e),s=new Date-t,a=Math.floor(s/6e4),o=Math.floor(s/36e5),l=Math.floor(s/864e5);return a<1?"Just now":a<60?`${a}m ago`:o<24?`${o}h ago`:l<7?`${l}d ago`:t.toLocaleDateString()}catch{return""}}function st(e,t=null){if(t)return t(e);let n=H(e);return n=n.replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>"),n=n.replace(/__(.+?)__/g,"<strong>$1</strong>"),n=n.replace(/\*(.+?)\*/g,"<em>$1</em>"),n=n.replace(/_(.+?)_/g,"<em>$1</em>"),n=n.replace(/`(.+?)`/g,"<code>$1</code>"),n=n.replace(/\[(.+?)\]\((.+?)\)/g,'<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'),n=n.replace(/\n/g,"<br>"),n}function at(e=""){let t=n=>e?`${n}_${e}`:n;return{get(n){try{return localStorage.getItem(t(n))}catch{return null}},set(n,s){try{let a=t(n);s===null?localStorage.removeItem(a):localStorage.setItem(a,s)}catch{}}}}function rt(e="csrftoken"){let t=document.cookie.split(";");for(let s of t){let[a,o]=s.trim().split("=");if(a===e)return decodeURIComponent(o)}let n=document.querySelector('meta[name="csrf-token"]');return n?n.getAttribute("content"):null}function lt({config:e,debugMode:t,isExpanded:n,isSpeaking:s,messagesCount:a,isLoading:o,currentAgent:l,onClose:c,onToggleExpand:_,onToggleDebug:i,onToggleTTS:u,onClear:r,onToggleSidebar:f}){let{title:d,primaryColor:m,embedded:S,showConversationSidebar:b,showClearButton:g,showDebugButton:w,enableDebugMode:N,showTTSButton:A,showExpandButton:j,enableTTS:O,elevenLabsApiKey:L,ttsProxyUrl:W}=e,F=L||W;return y`
|
|
3
|
+
<div class="cw-header" style=${{backgroundColor:m}}>
|
|
4
|
+
${b&&y`
|
|
5
|
+
<button
|
|
6
|
+
class="cw-header-btn cw-hamburger"
|
|
7
|
+
onClick=${f}
|
|
8
|
+
title="Conversations"
|
|
9
|
+
>
|
|
10
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="16" height="16">
|
|
11
|
+
<line x1="3" y1="6" x2="21" y2="6"></line>
|
|
12
|
+
<line x1="3" y1="12" x2="21" y2="12"></line>
|
|
13
|
+
<line x1="3" y1="18" x2="21" y2="18"></line>
|
|
14
|
+
</svg>
|
|
15
|
+
</button>
|
|
16
|
+
`}
|
|
17
|
+
|
|
18
|
+
<div class="cw-title-container">
|
|
19
|
+
<span class="cw-title">${H(d)}</span>
|
|
20
|
+
${l&&y`
|
|
21
|
+
<span class="cw-current-agent" title="Currently active agent">
|
|
22
|
+
<span class="cw-agent-indicator">🤖</span>
|
|
23
|
+
<span class="cw-agent-name">${H(l.name||l.key)}</span>
|
|
24
|
+
</span>
|
|
25
|
+
`}
|
|
957
26
|
</div>
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
<
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
27
|
+
|
|
28
|
+
<div class="cw-header-actions">
|
|
29
|
+
${g&&y`
|
|
30
|
+
<button
|
|
31
|
+
class="cw-header-btn"
|
|
32
|
+
onClick=${r}
|
|
33
|
+
title="Clear"
|
|
34
|
+
disabled=${o||a===0}
|
|
35
|
+
>🗑️</button>
|
|
36
|
+
`}
|
|
37
|
+
|
|
38
|
+
${w&&N&&y`
|
|
39
|
+
<button
|
|
40
|
+
class="cw-header-btn ${t?"cw-btn-active":""}"
|
|
41
|
+
onClick=${i}
|
|
42
|
+
title="Debug"
|
|
43
|
+
>🐛</button>
|
|
44
|
+
`}
|
|
45
|
+
|
|
46
|
+
${A&&F&&y`
|
|
47
|
+
<button
|
|
48
|
+
class="cw-header-btn ${O?"cw-btn-active":""}"
|
|
49
|
+
onClick=${u}
|
|
50
|
+
title="TTS"
|
|
51
|
+
>${O?"\u{1F50A}":"\u{1F507}"}</button>
|
|
52
|
+
`}
|
|
53
|
+
|
|
54
|
+
${j&&!S&&y`
|
|
55
|
+
<button
|
|
56
|
+
class="cw-header-btn"
|
|
57
|
+
onClick=${_}
|
|
58
|
+
title=${n?"Minimize":"Expand"}
|
|
59
|
+
>${n?"\u2296":"\u2295"}</button>
|
|
60
|
+
`}
|
|
61
|
+
|
|
62
|
+
${!S&&y`
|
|
63
|
+
<button
|
|
64
|
+
class="cw-header-btn"
|
|
65
|
+
onClick=${c}
|
|
66
|
+
title="Close"
|
|
67
|
+
>✕</button>
|
|
68
|
+
`}
|
|
995
69
|
</div>
|
|
996
|
-
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
</button>
|
|
1008
|
-
`).
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
${config.autoRunMode === 'automatic' ? 'checked' : ''}
|
|
1017
|
-
onchange="ChatWidget.setAutoRunMode('automatic')">
|
|
1018
|
-
<span>⚡ Automatic</span>
|
|
1019
|
-
</label>
|
|
1020
|
-
<label class="cw-control-label">
|
|
1021
|
-
<input type="radio" name="autorun-mode" value="confirm"
|
|
1022
|
-
${config.autoRunMode === 'confirm' ? 'checked' : ''}
|
|
1023
|
-
onchange="ChatWidget.setAutoRunMode('confirm')">
|
|
1024
|
-
<span>👆 Confirm Next</span>
|
|
1025
|
-
</label>
|
|
1026
|
-
<label class="cw-control-label">
|
|
1027
|
-
<input type="radio" name="autorun-mode" value="manual"
|
|
1028
|
-
${config.autoRunMode === 'manual' ? 'checked' : ''}
|
|
1029
|
-
onchange="ChatWidget.setAutoRunMode('manual')">
|
|
1030
|
-
<span>✋ Manual</span>
|
|
1031
|
-
</label>
|
|
70
|
+
</div>
|
|
71
|
+
`}function Te({msg:e,show:t,onToggle:n}){return t?y`
|
|
72
|
+
<div class="cw-debug-payload">
|
|
73
|
+
<button class="cw-debug-payload-close" onClick=${n}>×</button>
|
|
74
|
+
<pre class="cw-debug-payload-content">${JSON.stringify(e,null,2)}</pre>
|
|
75
|
+
</div>
|
|
76
|
+
`:y`
|
|
77
|
+
<button
|
|
78
|
+
class="cw-debug-payload-btn"
|
|
79
|
+
onClick=${n}
|
|
80
|
+
title="Show message payload"
|
|
81
|
+
>{ }</button>
|
|
82
|
+
`}function it({msg:e,debugMode:t,markdownParser:n}){let[s,a]=C(!1),[o,l]=C(!1),c=e.role==="user",_=e.role==="system",i=e.type==="tool_call",u=e.type==="tool_result",r=e.type==="error",f=e.type==="sub_agent_start",d=e.type==="sub_agent_end",m=e.type==="agent_context";if(_&&!t)return null;if(f||d||m)return y`
|
|
83
|
+
<div class="cw-agent-context ${f?"cw-agent-delegating":""} ${d?"cw-agent-returned":""}" style="position: relative;">
|
|
84
|
+
<span class="cw-agent-context-icon">${f?"\u{1F517}":d?"\u2713":"\u{1F916}"}</span>
|
|
85
|
+
<span class="cw-agent-context-text">${e.content}</span>
|
|
86
|
+
${e.metadata?.agentName&&y`
|
|
87
|
+
<span class="cw-agent-context-name">${e.metadata.agentName}</span>
|
|
88
|
+
`}
|
|
89
|
+
${t&&y`<${Te} msg=${e} show=${o} onToggle=${()=>l(!o)} />`}
|
|
1032
90
|
</div>
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
</
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
<div class="cw-dropdown-separator"></div>
|
|
1044
|
-
<button class="cw-dropdown-item cw-dropdown-item-danger" data-action="stop-autorun">
|
|
1045
|
-
⏹️ Stop Demo
|
|
1046
|
-
</button>
|
|
1047
|
-
` : '';
|
|
1048
|
-
|
|
1049
|
-
return `
|
|
1050
|
-
<div class="cw-dropdown">
|
|
1051
|
-
<button class="cw-header-btn ${state.autoRunActive ? 'cw-btn-active' : ''}"
|
|
1052
|
-
data-action="toggle-journey-dropdown"
|
|
1053
|
-
title="Demo Flows"
|
|
1054
|
-
${state.isLoading || state.isSimulating ? 'disabled' : ''}>
|
|
1055
|
-
${state.isSimulating ? '<span class="cw-spinner"></span>' : '▶'}
|
|
1056
|
-
</button>
|
|
1057
|
-
<div class="cw-dropdown-menu cw-dropdown-hidden" id="cw-journey-dropdown">
|
|
1058
|
-
<div class="cw-dropdown-label">Demo Flows</div>
|
|
1059
|
-
<div class="cw-dropdown-separator"></div>
|
|
1060
|
-
${journeyItems}
|
|
1061
|
-
${controlsSection}
|
|
1062
|
-
</div>
|
|
91
|
+
`;if(i||u){let w=e.metadata?.arguments||e.metadata?.result,N=A=>{if(typeof A=="string")try{return JSON.stringify(JSON.parse(A),null,2)}catch{return A}return JSON.stringify(A,null,2)};return y`
|
|
92
|
+
<div class="cw-tool-message ${u?"cw-tool-result":"cw-tool-call"}" style="position: relative;">
|
|
93
|
+
<span class="cw-tool-label" onClick=${()=>w&&a(!s)}>
|
|
94
|
+
${e.content}
|
|
95
|
+
${w&&y`<span class="cw-tool-expand">${s?"\u25BC":"\u25B6"}</span>`}
|
|
96
|
+
</span>
|
|
97
|
+
${s&&w&&y`
|
|
98
|
+
<pre class="cw-tool-details">${H(N(i?e.metadata.arguments:e.metadata.result))}</pre>
|
|
99
|
+
`}
|
|
100
|
+
${t&&y`<${Te} msg=${e} show=${o} onToggle=${()=>l(!o)} />`}
|
|
1063
101
|
</div>
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
container.innerHTML = `
|
|
1073
|
-
<button class="cw-fab" style="background-color: ${config.primaryColor}">
|
|
1074
|
-
<svg class="cw-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1075
|
-
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
1076
|
-
</svg>
|
|
1077
|
-
</button>
|
|
1078
|
-
`;
|
|
1079
|
-
container.querySelector('.cw-fab').addEventListener('click', openWidget);
|
|
1080
|
-
return;
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
// Render chat widget
|
|
1084
|
-
const messagesHtml = state.messages.length === 0
|
|
1085
|
-
? `
|
|
102
|
+
`}let S=["cw-message",c&&"cw-message-user",r&&"cw-message-error"].filter(Boolean).join(" "),b=`cw-message-row ${c?"cw-message-row-user":""}`,g=e.role==="assistant"?st(e.content,n):H(e.content);return y`
|
|
103
|
+
<div class=${b} style="position: relative;">
|
|
104
|
+
<div class=${S} dangerouslySetInnerHTML=${{__html:g}} />
|
|
105
|
+
${t&&y`<${Te} msg=${e} show=${o} onToggle=${()=>l(!o)} />`}
|
|
106
|
+
</div>
|
|
107
|
+
`}function ct({messages:e,isLoading:t,hasMoreMessages:n,loadingMoreMessages:s,onLoadMore:a,debugMode:o,markdownParser:l,emptyStateTitle:c,emptyStateMessage:_}){let i=z(null),u=z(!0),r=d=>{let m=d.target,S=m.scrollHeight-m.scrollTop-m.clientHeight<100;if(u.current=S,m.scrollTop<50&&n&&!s){let b=m.scrollHeight;a().then(()=>{let g=m.scrollHeight;m.scrollTop=g-b+m.scrollTop})}};R(()=>{let d=i.current;d&&u.current&&requestAnimationFrame(()=>{d.scrollTop=d.scrollHeight})},[e,t]),R(()=>{let d=i.current;d&&e.length<=2&&(u.current=!0,requestAnimationFrame(()=>{d.scrollTop=d.scrollHeight}))},[e.length]);let f=e.length===0;return y`
|
|
108
|
+
<div class="cw-messages" ref=${i} onScroll=${r}>
|
|
109
|
+
${f&&y`
|
|
1086
110
|
<div class="cw-empty-state">
|
|
1087
111
|
<svg class="cw-empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1088
112
|
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
1089
113
|
</svg>
|
|
1090
|
-
<h3>${
|
|
1091
|
-
<p>${
|
|
114
|
+
<h3>${H(c)}</h3>
|
|
115
|
+
<p>${H(_)}</p>
|
|
1092
116
|
</div>
|
|
1093
|
-
`
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
<div class="cw-typing">
|
|
1099
|
-
<span class="cw-spinner"></span>
|
|
1100
|
-
<span>Thinking...</span>
|
|
117
|
+
`}
|
|
118
|
+
|
|
119
|
+
${!f&&n&&y`
|
|
120
|
+
<div class="cw-load-more" onClick=${a}>
|
|
121
|
+
${s?y`<span class="cw-spinner"></span><span>Loading...</span>`:y`<span>↑ Scroll up or click to load older messages</span>`}
|
|
1101
122
|
</div>
|
|
123
|
+
`}
|
|
124
|
+
|
|
125
|
+
${e.map(d=>y`
|
|
126
|
+
<${it}
|
|
127
|
+
key=${d.id}
|
|
128
|
+
msg=${d}
|
|
129
|
+
debugMode=${o}
|
|
130
|
+
markdownParser=${l}
|
|
131
|
+
/>
|
|
132
|
+
`)}
|
|
133
|
+
|
|
134
|
+
${t&&y`
|
|
135
|
+
<div class="cw-message-row">
|
|
136
|
+
<div class="cw-typing">
|
|
137
|
+
<span class="cw-spinner"></span>
|
|
138
|
+
<span>Thinking...</span>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
`}
|
|
142
|
+
</div>
|
|
143
|
+
`}function ut({onSend:e,onCancel:t,isLoading:n,placeholder:s,primaryColor:a}){let[o,l]=C(""),[c,_]=C(!1),i=z(null);R(()=>{!n&&i.current&&i.current.focus()},[n]),R(()=>{i.current&&(i.current.style.height="auto",i.current.style.height=Math.min(i.current.scrollHeight,150)+"px")},[o]);let u=m=>{m.preventDefault(),o.trim()&&!n&&(e(o),l(""),i.current&&(i.current.style.height="auto"))},r=m=>{m.key==="Enter"&&!m.shiftKey&&(m.preventDefault(),u(m))},f=m=>{n&&t&&(m.preventDefault(),t())},d=y`
|
|
144
|
+
<svg width="14" height="14" viewBox="0 0 14 14" fill="currentColor">
|
|
145
|
+
<rect x="2" y="2" width="10" height="10" rx="1" />
|
|
146
|
+
</svg>
|
|
147
|
+
`;return y`
|
|
148
|
+
<form class="cw-input-form" onSubmit=${u}>
|
|
149
|
+
<textarea
|
|
150
|
+
ref=${i}
|
|
151
|
+
class="cw-input"
|
|
152
|
+
placeholder=${H(s)}
|
|
153
|
+
value=${o}
|
|
154
|
+
onInput=${m=>l(m.target.value)}
|
|
155
|
+
onKeyDown=${r}
|
|
156
|
+
disabled=${n}
|
|
157
|
+
rows="1"
|
|
158
|
+
/>
|
|
159
|
+
<button
|
|
160
|
+
type=${n?"button":"submit"}
|
|
161
|
+
class=${`cw-send-btn ${n?"cw-send-btn-loading":""} ${n&&c?"cw-send-btn-stop":""}`}
|
|
162
|
+
style=${{backgroundColor:n&&c?"#dc2626":a}}
|
|
163
|
+
onClick=${f}
|
|
164
|
+
onMouseEnter=${()=>_(!0)}
|
|
165
|
+
onMouseLeave=${()=>_(!1)}
|
|
166
|
+
title=${n?"Stop":"Send"}
|
|
167
|
+
>
|
|
168
|
+
${n?c?d:y`<span class="cw-spinner"></span>`:"\u27A4"}
|
|
169
|
+
</button>
|
|
170
|
+
</form>
|
|
171
|
+
`}function _t({isOpen:e,conversations:t,conversationsLoading:n,currentConversationId:s,onClose:a,onNewConversation:o,onSwitchConversation:l}){return y`
|
|
172
|
+
<div class="cw-sidebar ${e?"cw-sidebar-open":""}">
|
|
173
|
+
<div class="cw-sidebar-header">
|
|
174
|
+
<span>Conversations</span>
|
|
175
|
+
<button class="cw-sidebar-close" onClick=${a}>✕</button>
|
|
1102
176
|
</div>
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
${
|
|
1116
|
-
|
|
177
|
+
|
|
178
|
+
<button class="cw-new-conversation" onClick=${o}>
|
|
179
|
+
<span>+ New Conversation</span>
|
|
180
|
+
</button>
|
|
181
|
+
|
|
182
|
+
<div class="cw-conversation-list">
|
|
183
|
+
${n&&y`
|
|
184
|
+
<div class="cw-sidebar-loading">
|
|
185
|
+
<span class="cw-spinner"></span>
|
|
186
|
+
</div>
|
|
187
|
+
`}
|
|
188
|
+
|
|
189
|
+
${!n&&t.length===0&&y`
|
|
190
|
+
<div class="cw-sidebar-empty">No conversations yet</div>
|
|
191
|
+
`}
|
|
192
|
+
|
|
193
|
+
${t.map(c=>y`
|
|
194
|
+
<div
|
|
195
|
+
key=${c.id}
|
|
196
|
+
class="cw-conversation-item ${c.id===s?"cw-conversation-active":""}"
|
|
197
|
+
onClick=${()=>l(c.id)}
|
|
198
|
+
>
|
|
199
|
+
<div class="cw-conversation-title">${H(c.title||"Untitled")}</div>
|
|
200
|
+
<div class="cw-conversation-date">${ot(c.updatedAt||c.createdAt)}</div>
|
|
201
|
+
</div>
|
|
202
|
+
`)}
|
|
1117
203
|
</div>
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
<
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
</button>
|
|
1151
|
-
` : ''}
|
|
1152
|
-
${config.showVoiceSettings && (config.elevenLabsApiKey || config.ttsProxyUrl) ? `
|
|
1153
|
-
<button class="cw-header-btn ${state.voiceSettingsOpen ? 'cw-btn-active' : ''}" data-action="toggle-voice-settings" title="Voice Settings">
|
|
1154
|
-
🎙️
|
|
1155
|
-
</button>
|
|
1156
|
-
` : ''}
|
|
1157
|
-
${renderJourneyDropdown()}
|
|
1158
|
-
${config.showExpandButton ? `
|
|
1159
|
-
<button class="cw-header-btn" data-action="toggle-expand" title="${state.isExpanded ? 'Minimize' : 'Expand'}">
|
|
1160
|
-
${state.isExpanded ? '⊖' : '⊕'}
|
|
1161
|
-
</button>
|
|
1162
|
-
` : ''}
|
|
1163
|
-
<button class="cw-header-btn" data-action="close" title="Close">
|
|
1164
|
-
✕
|
|
204
|
+
</div>
|
|
205
|
+
|
|
206
|
+
<div
|
|
207
|
+
class="cw-sidebar-overlay ${e?"cw-sidebar-overlay-visible":""}"
|
|
208
|
+
onClick=${a}
|
|
209
|
+
/>
|
|
210
|
+
`}function dt({availableModels:e,selectedModel:t,onSelectModel:n,disabled:s}){let[a,o]=C(!1);if(!e||e.length===0)return null;let c=e.find(u=>u.id===t)?.name||"Select Model",_=()=>{s||o(!a)},i=u=>{n(u),o(!1)};return y`
|
|
211
|
+
<div class="cw-model-selector">
|
|
212
|
+
<button
|
|
213
|
+
class="cw-model-btn"
|
|
214
|
+
onClick=${_}
|
|
215
|
+
disabled=${s}
|
|
216
|
+
title="Select Model"
|
|
217
|
+
>
|
|
218
|
+
<span class="cw-model-icon">🤖</span>
|
|
219
|
+
<span class="cw-model-name">${H(c)}</span>
|
|
220
|
+
<span class="cw-model-chevron">${a?"\u25B2":"\u25BC"}</span>
|
|
221
|
+
</button>
|
|
222
|
+
|
|
223
|
+
${a&&y`
|
|
224
|
+
<div class="cw-model-dropdown">
|
|
225
|
+
${e.map(u=>y`
|
|
226
|
+
<button
|
|
227
|
+
key=${u.id}
|
|
228
|
+
class="cw-model-option ${u.id===t?"cw-model-option-selected":""}"
|
|
229
|
+
onClick=${()=>i(u.id)}
|
|
230
|
+
>
|
|
231
|
+
<span class="cw-model-option-name">${H(u.name)}</span>
|
|
232
|
+
<span class="cw-model-option-provider">${H(u.provider)}</span>
|
|
233
|
+
${u.description&&y`
|
|
234
|
+
<span class="cw-model-option-desc">${H(u.description)}</span>
|
|
235
|
+
`}
|
|
1165
236
|
</button>
|
|
1166
|
-
|
|
1167
|
-
</div>
|
|
1168
|
-
${renderVoiceSettings()}
|
|
1169
|
-
${statusBar}
|
|
1170
|
-
<div class="cw-messages" id="cw-messages">
|
|
1171
|
-
${messagesHtml}
|
|
1172
|
-
${typingIndicator}
|
|
237
|
+
`)}
|
|
1173
238
|
</div>
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
<form class="cw-input-form" id="cw-input-form">
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
// Close dropdown when clicking outside
|
|
1256
|
-
document.addEventListener('click', (e) => {
|
|
1257
|
-
if (!e.target.closest('.cw-dropdown')) {
|
|
1258
|
-
const dropdown = document.getElementById('cw-journey-dropdown');
|
|
1259
|
-
if (dropdown) dropdown.classList.add('cw-dropdown-hidden');
|
|
1260
|
-
}
|
|
1261
|
-
});
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
// ============================================================================
|
|
1265
|
-
// Public API
|
|
1266
|
-
// ============================================================================
|
|
1267
|
-
|
|
1268
|
-
function init(userConfig = {}) {
|
|
1269
|
-
// Deep merge apiPaths to allow partial overrides
|
|
1270
|
-
const mergedApiPaths = {
|
|
1271
|
-
...DEFAULT_CONFIG.apiPaths,
|
|
1272
|
-
...(userConfig.apiPaths || {}),
|
|
1273
|
-
};
|
|
1274
|
-
|
|
1275
|
-
config = {
|
|
1276
|
-
...DEFAULT_CONFIG,
|
|
1277
|
-
...userConfig,
|
|
1278
|
-
apiPaths: mergedApiPaths,
|
|
1279
|
-
};
|
|
1280
|
-
state.journeyType = config.defaultJourneyType;
|
|
1281
|
-
|
|
1282
|
-
// Initialize auth token from config
|
|
1283
|
-
if (config.authToken) {
|
|
1284
|
-
state.authToken = config.authToken;
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
// Restore conversation ID
|
|
1288
|
-
state.conversationId = getStoredValue(config.conversationIdKey);
|
|
1289
|
-
|
|
1290
|
-
// Create container
|
|
1291
|
-
container = document.createElement('div');
|
|
1292
|
-
container.id = 'chat-widget-container';
|
|
1293
|
-
container.className = `cw-container cw-position-${config.position}`;
|
|
1294
|
-
document.body.appendChild(container);
|
|
1295
|
-
|
|
1296
|
-
// Initial render
|
|
1297
|
-
render();
|
|
1298
|
-
|
|
1299
|
-
// Fetch available voices if TTS is configured
|
|
1300
|
-
if (config.elevenLabsApiKey || config.ttsProxyUrl) {
|
|
1301
|
-
fetchAvailableVoices();
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
console.log('[ChatWidget] Initialized with config:', config);
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
function destroy() {
|
|
1308
|
-
if (state.eventSource) {
|
|
1309
|
-
state.eventSource.close();
|
|
1310
|
-
}
|
|
1311
|
-
if (container) {
|
|
1312
|
-
container.remove();
|
|
1313
|
-
container = null;
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
function open() {
|
|
1318
|
-
openWidget();
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
function close() {
|
|
1322
|
-
closeWidget();
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
function send(message) {
|
|
1326
|
-
if (!state.isOpen) {
|
|
1327
|
-
openWidget();
|
|
1328
|
-
}
|
|
1329
|
-
sendMessage(message);
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
/**
|
|
1333
|
-
* Update authentication configuration
|
|
1334
|
-
* @param {Object} authConfig - { strategy?: string, token?: string }
|
|
1335
|
-
*/
|
|
1336
|
-
function setAuth(authConfig = {}) {
|
|
1337
|
-
if (authConfig.strategy) {
|
|
1338
|
-
config.authStrategy = authConfig.strategy;
|
|
1339
|
-
}
|
|
1340
|
-
if (authConfig.token !== undefined) {
|
|
1341
|
-
config.authToken = authConfig.token;
|
|
1342
|
-
state.authToken = authConfig.token;
|
|
1343
|
-
|
|
1344
|
-
// For anonymous strategy, also persist to storage
|
|
1345
|
-
if (getAuthStrategy() === 'anonymous' && authConfig.token) {
|
|
1346
|
-
const storageKey = config.anonymousTokenKey || config.sessionTokenKey;
|
|
1347
|
-
setStoredValue(storageKey, authConfig.token);
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
console.log('[ChatWidget] Auth updated:', { strategy: getAuthStrategy(), hasToken: !!state.authToken });
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
/**
|
|
1354
|
-
* Clear authentication
|
|
1355
|
-
*/
|
|
1356
|
-
function clearAuth() {
|
|
1357
|
-
config.authToken = null;
|
|
1358
|
-
state.authToken = null;
|
|
1359
|
-
state.sessionToken = null;
|
|
1360
|
-
|
|
1361
|
-
// Clear from storage
|
|
1362
|
-
const storageKey = config.anonymousTokenKey || config.sessionTokenKey;
|
|
1363
|
-
setStoredValue(storageKey, null);
|
|
1364
|
-
|
|
1365
|
-
console.log('[ChatWidget] Auth cleared');
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
// Export public API
|
|
1369
|
-
global.ChatWidget = {
|
|
1370
|
-
init,
|
|
1371
|
-
destroy,
|
|
1372
|
-
open,
|
|
1373
|
-
close,
|
|
1374
|
-
send,
|
|
1375
|
-
clearMessages,
|
|
1376
|
-
startDemoFlow,
|
|
1377
|
-
stopAutoRun,
|
|
1378
|
-
continueAutoRun,
|
|
1379
|
-
setAutoRunMode,
|
|
1380
|
-
setAutoRunDelay,
|
|
1381
|
-
toggleTTS,
|
|
1382
|
-
stopSpeech,
|
|
1383
|
-
setVoice,
|
|
1384
|
-
setAuth,
|
|
1385
|
-
clearAuth,
|
|
1386
|
-
getState: () => ({ ...state }),
|
|
1387
|
-
getConfig: () => ({ ...config }),
|
|
1388
|
-
};
|
|
1389
|
-
|
|
1390
|
-
})(typeof window !== 'undefined' ? window : this);
|
|
239
|
+
`}
|
|
240
|
+
</div>
|
|
241
|
+
`}function pt(e,t,n){let[s,a]=C([]),[o,l]=C(!1),[c,_]=C(null),[i,u]=C(()=>n?.get(e.conversationIdKey)||null),[r,f]=C(!1),[d,m]=C(!1),[S,b]=C(0),g=z(null),w=z(null);R(()=>{i&&n?.set(e.conversationIdKey,i)},[i,e.conversationIdKey,n]);let N=U(async(p,$,E)=>{g.current&&g.current.close();let I=e.apiPaths.runEvents.replace("{runId}",p),K=`${e.backendUrl}${I}`;$&&(K+=`?anonymous_token=${encodeURIComponent($)}`);let k=new EventSource(K);g.current=k;let B="";k.addEventListener("assistant.message",v=>{try{let h=JSON.parse(v.data);e.onEvent&&e.onEvent("assistant.message",h.payload);let x=h.payload.content;x&&(B+=x,a(V=>{let Q=V[V.length-1];return Q?.role==="assistant"&&Q.id.startsWith("assistant-stream-")?[...V.slice(0,-1),{...Q,content:B}]:[...V,{id:"assistant-stream-"+Date.now(),role:"assistant",content:B,timestamp:new Date,type:"message"}]}))}catch(h){console.error("[ChatWidget] Parse error:",h)}}),k.addEventListener("tool.call",v=>{try{let h=JSON.parse(v.data);e.onEvent&&e.onEvent("tool.call",h.payload),a(x=>[...x,{id:"tool-call-"+Date.now(),role:"assistant",content:`\u{1F527} ${h.payload.name}`,timestamp:new Date,type:"tool_call",metadata:{toolName:h.payload.name,arguments:h.payload.arguments,toolCallId:h.payload.id}}])}catch(h){console.error("[ChatWidget] Parse error:",h)}}),k.addEventListener("tool.result",v=>{try{let h=JSON.parse(v.data);e.onEvent&&e.onEvent("tool.result",h.payload);let x=h.payload.result,V=x?.error;a(Q=>[...Q,{id:"tool-result-"+Date.now(),role:"system",content:V?`\u274C ${x.error}`:"\u2713 Done",timestamp:new Date,type:"tool_result",metadata:{toolName:h.payload.name,result:x,toolCallId:h.payload.tool_call_id}}])}catch(h){console.error("[ChatWidget] Parse error:",h)}}),k.addEventListener("custom",v=>{try{let h=JSON.parse(v.data);e.onEvent&&e.onEvent("custom",h.payload),h.payload?.type==="ui_control"&&e.onUIControl&&e.onUIControl(h.payload),h.payload?.type==="agent_context"&&a(x=>[...x,{id:"agent-context-"+Date.now(),role:"system",content:`\u{1F517} ${h.payload.agent_name||"Sub-agent"} is now handling this request`,timestamp:new Date,type:"agent_context",metadata:{agentKey:h.payload.agent_key,agentName:h.payload.agent_name,action:h.payload.action}}])}catch(h){console.error("[ChatWidget] Parse error:",h)}}),k.addEventListener("sub_agent.start",v=>{try{let h=JSON.parse(v.data);e.onEvent&&e.onEvent("sub_agent.start",h.payload),a(x=>[...x,{id:"sub-agent-start-"+Date.now(),role:"system",content:`\u{1F517} Delegating to ${h.payload.agent_name||h.payload.sub_agent_key||"sub-agent"}...`,timestamp:new Date,type:"sub_agent_start",metadata:{subAgentKey:h.payload.sub_agent_key,agentName:h.payload.agent_name,invocationMode:h.payload.invocation_mode}}])}catch(h){console.error("[ChatWidget] Parse error:",h)}}),k.addEventListener("sub_agent.end",v=>{try{let h=JSON.parse(v.data);e.onEvent&&e.onEvent("sub_agent.end",h.payload),a(x=>[...x,{id:"sub-agent-end-"+Date.now(),role:"system",content:`\u2713 ${h.payload.agent_name||"Sub-agent"} completed`,timestamp:new Date,type:"sub_agent_end",metadata:{subAgentKey:h.payload.sub_agent_key,agentName:h.payload.agent_name}}])}catch(h){console.error("[ChatWidget] Parse error:",h)}});let J=v=>{try{let h=JSON.parse(v.data);if(e.onEvent&&e.onEvent(h.type,h.payload),h.type==="run.failed"){let x=h.payload.error||"Agent run failed";_(x),a(V=>[...V,{id:"error-"+Date.now(),role:"system",content:`\u274C Error: ${x}`,timestamp:new Date,type:"error"}])}}catch(h){console.error("[ChatWidget] Parse error:",h)}l(!1),k.close(),g.current=null,B&&E&&E(B)};k.addEventListener("run.succeeded",J),k.addEventListener("run.failed",J),k.addEventListener("run.cancelled",J),k.addEventListener("run.timed_out",J),k.onerror=()=>{l(!1),k.close(),g.current=null}},[e]),A=U(async(p,$={})=>{if(!p.trim()||o)return;let{model:E,onAssistantMessage:I}=typeof $=="function"?{onAssistantMessage:$}:$;l(!0),_(null);let K={id:de(),role:"user",content:p.trim(),timestamp:new Date,type:"message"};a(k=>[...k,K]);try{let k=await t.getOrCreateSession(),B={agentKey:e.agentKey,conversationId:i,messages:[{role:"user",content:p.trim()}],metadata:{...e.metadata,journeyType:e.defaultJourneyType}};E&&(B.model=E);let J=await fetch(`${e.backendUrl}${e.apiPaths.runs}`,t.getFetchOptions({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(B)}));if(!J.ok){let x=await J.json().catch(()=>({}));throw new Error(x.error||`HTTP ${J.status}`)}let v=await J.json();w.current=v.id;let h=v.conversationId||v.conversation_id;!i&&h&&u(h),await N(v.id,k,I)}catch(k){_(k.message||"Failed to send message"),l(!1)}finally{w.current=null}},[e,t,i,o,N]),j=U(async()=>{let p=w.current;if(!(!p||!o))try{let $=e.apiPaths.cancelRun?e.apiPaths.cancelRun.replace("{runId}",p):`${e.apiPaths.runs}${p}/cancel/`;(await fetch(`${e.backendUrl}${$}`,t.getFetchOptions({method:"POST",headers:{"Content-Type":"application/json"}}))).ok&&(g.current&&(g.current.close(),g.current=null),l(!1),w.current=null,a(I=>[...I,{id:"cancelled-"+Date.now(),role:"system",content:"\u23F9 Run cancelled",timestamp:new Date,type:"cancelled"}]))}catch($){console.error("[ChatWidget] Failed to cancel run:",$)}},[e,t,o]),O=U(()=>{a([]),u(null),_(null),f(!1),b(0),n?.set(e.conversationIdKey,null)},[e.conversationIdKey,n]),L=p=>{let $={id:de(),role:p.role,timestamp:p.timestamp?new Date(p.timestamp):new Date};if(p.role==="tool")return{...$,role:"system",content:"\u2713 Done",type:"tool_result",metadata:{result:p.content,toolCallId:p.tool_call_id}};if(p.role==="assistant"&&p.tool_calls&&p.tool_calls.length>0)return p.tool_calls.map(I=>({id:de(),role:"assistant",content:`\u{1F527} ${I.function?.name||I.name||"tool"}`,timestamp:$.timestamp,type:"tool_call",metadata:{toolName:I.function?.name||I.name,arguments:I.function?.arguments||I.arguments,toolCallId:I.id}}));let E=typeof p.content=="string"?p.content:JSON.stringify(p.content);return p.role==="assistant"&&!E?.trim()?null:{...$,content:E,type:"message"}},W=U(async p=>{l(!0),a([]),u(p);try{let $=await t.getOrCreateSession(),I=`${e.backendUrl}${e.apiPaths.conversations}${p}/?limit=10&offset=0`,K=await fetch(I,t.getFetchOptions({method:"GET"}));if(K.ok){let k=await K.json();k.messages&&a(k.messages.flatMap(L).filter(Boolean)),f(k.has_more||k.hasMore||!1),b(k.messages?.length||0)}else K.status===404&&(u(null),n?.set(e.conversationIdKey,null))}catch($){console.error("[ChatWidget] Failed to load conversation:",$)}finally{l(!1)}},[e,t,n]),F=U(async()=>{if(!(!i||d||!r)){m(!0);try{let $=`${e.backendUrl}${e.apiPaths.conversations}${i}/?limit=10&offset=${S}`,E=await fetch($,t.getFetchOptions({method:"GET"}));if(E.ok){let I=await E.json();if(I.messages?.length>0){let K=I.messages.flatMap(L).filter(Boolean);a(k=>[...K,...k]),b(k=>k+I.messages.length),f(I.has_more||I.hasMore||!1)}else f(!1)}}catch(p){console.error("[ChatWidget] Failed to load more messages:",p)}finally{m(!1)}}},[e,t,i,S,d,r]);return R(()=>()=>{g.current&&g.current.close()},[]),{messages:s,isLoading:o,error:c,conversationId:i,hasMoreMessages:r,loadingMoreMessages:d,sendMessage:A,cancelRun:j,clearMessages:O,loadConversation:W,loadMoreMessages:F,setConversationId:u}}function ft(e,t,n){let[s,a]=C([]),[o,l]=C(null),[c,_]=C(null),[i,u]=C(!1);R(()=>{(async()=>{if(e.showModelSelector){u(!0);try{let m=await fetch(`${e.backendUrl}${e.apiPaths.models}`,t.getFetchOptions({method:"GET"}));if(m.ok){let S=await m.json(),b=S.models||[];a(b),_(S.default);let g=n?.get(e.modelKey);g&&b.some(w=>w.id===g)?l(g):l(S.default)}}catch(m){console.warn("[ChatWidget] Failed to load models:",m)}finally{u(!1)}}})()},[e.backendUrl,e.apiPaths.models,e.showModelSelector,e.modelKey,t,n]);let r=U(d=>{l(d),n?.set(e.modelKey,d)},[e.modelKey,n]),f=U(()=>s.find(d=>d.id===o)||null,[s,o]);return{availableModels:s,selectedModel:o,defaultModel:c,isLoading:i,selectModel:r,getSelectedModelInfo:f}}function ht(e,t,n){let s=()=>e.authStrategy?e.authStrategy:e.authToken?"token":e.apiPaths.anonymousSession||e.anonymousSessionEndpoint?"anonymous":"none",a=()=>{let c=s(),_={},i=e.authToken||t().authToken;if(c==="token"&&i){let u=e.authHeader||"Authorization",r=e.authTokenPrefix!==void 0?e.authTokenPrefix:"Token";_[u]=r?`${r} ${i}`:i}else if(c==="jwt"&&i){let u=e.authHeader||"Authorization",r=e.authTokenPrefix!==void 0?e.authTokenPrefix:"Bearer";_[u]=r?`${r} ${i}`:i}else if(c==="anonymous"&&i){let u=e.authHeader||e.anonymousTokenHeader||"X-Anonymous-Token";_[u]=i}if(c==="session"){let u=rt(e.csrfCookieName);u&&(_["X-CSRFToken"]=u)}return _};return{getAuthStrategy:s,getAuthHeaders:a,getFetchOptions:(c={})=>{let _=s(),i={...c};return i.headers={...i.headers,...a()},_==="session"&&(i.credentials="include"),i},getOrCreateSession:async()=>{let c=s(),_=t();if(c!=="anonymous")return e.authToken||_.authToken;if(_.authToken)return _.authToken;let i=e.anonymousTokenKey||e.sessionTokenKey,u=_.storage?.get(i);if(u)return n(r=>({...r,authToken:u})),u;try{let r=e.anonymousSessionEndpoint||e.apiPaths.anonymousSession,f=await fetch(`${e.backendUrl}${r}`,{method:"POST",headers:{"Content-Type":"application/json"}});if(f.ok){let d=await f.json();return n(m=>({...m,authToken:d.token})),_.storage?.set(i,d.token),d.token}}catch(r){console.warn("[ChatWidget] Failed to create session:",r)}return null}}}function mt({config:e,onStateChange:t,markdownParser:n,apiRef:s}){let[a,o]=C(e.embedded||e.forceOpen===!0),[l,c]=C(!1),[_,i]=C(!1),[u,r]=C(!1),[f,d]=C([]),[m,S]=C(!1),[b,g]=C(e.enableTTS),[w,N]=C(!1),[A,j]=C(null);R(()=>{e.forceOpen!==void 0&&o(e.forceOpen)},[e.forceOpen]);let O=ne(()=>at(e.containerId),[e.containerId]),[L,W]=C(e.authToken||null),F=ne(()=>ht(e,()=>({authToken:L,storage:O}),x=>{let V=x({authToken:L,storage:O});V.authToken!==L&&W(V.authToken)}),[e,L,O]),p=pt(e,F,O),$=ft(e,F,O);R(()=>{for(let v=p.messages.length-1;v>=0;v--){let h=p.messages[v];if(h.type==="sub_agent_start"){j({key:h.metadata?.subAgentKey,name:h.metadata?.agentName});return}if(h.type==="sub_agent_end"){j(null);return}}},[p.messages]),R(()=>{let v=O.get(e.conversationIdKey);v&&p.loadConversation(v)},[]),R(()=>{t&&t({isOpen:a,isExpanded:l,debugMode:_,messages:p.messages,conversationId:p.conversationId,isLoading:p.isLoading,error:p.error})},[a,l,_,p.messages,p.conversationId,p.isLoading,p.error]);let E=U(async()=>{if(e.showConversationSidebar){S(!0);try{let v=`${e.backendUrl}${e.apiPaths.conversations}?agent_key=${encodeURIComponent(e.agentKey)}`,h=await fetch(v,F.getFetchOptions({method:"GET"}));if(h.ok){let x=await h.json();d(x.results||x)}}catch(v){console.error("[ChatWidget] Failed to load conversations:",v),d([])}finally{S(!1)}}},[e,F]),I=U(()=>{let v=!u;r(v),v&&E()},[u,E]),K=U(v=>{v!==p.conversationId&&p.loadConversation(v),r(!1)},[p]),k=U(()=>{p.clearMessages(),r(!1)},[p]),B=U(v=>{p.sendMessage(v,{model:$.selectedModel,onAssistantMessage:h=>{}})},[p,b,$.selectedModel]);if(R(()=>{s&&(s.current={open:()=>o(!0),close:()=>o(!1),send:v=>B(v),clearMessages:()=>p.clearMessages(),toggleTTS:()=>g(v=>!v),stopSpeech:()=>N(!1),setAuth:v=>{v.token!==void 0&&W(v.token)},clearAuth:()=>W(null)})},[p,s,B]),!e.embedded&&!a)return y`
|
|
242
|
+
<button
|
|
243
|
+
class="cw-fab"
|
|
244
|
+
style=${{backgroundColor:e.primaryColor}}
|
|
245
|
+
onClick=${()=>o(!0)}
|
|
246
|
+
>
|
|
247
|
+
<svg class="cw-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
248
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
249
|
+
</svg>
|
|
250
|
+
</button>
|
|
251
|
+
`;let J=["cw-widget",l&&"cw-widget-expanded",e.embedded&&"cw-widget-embedded"].filter(Boolean).join(" ");return y`
|
|
252
|
+
<div class=${J} style=${{"--cw-primary":e.primaryColor}}>
|
|
253
|
+
${e.showConversationSidebar&&y`
|
|
254
|
+
<${_t}
|
|
255
|
+
isOpen=${u}
|
|
256
|
+
conversations=${f}
|
|
257
|
+
conversationsLoading=${m}
|
|
258
|
+
currentConversationId=${p.conversationId}
|
|
259
|
+
onClose=${()=>r(!1)}
|
|
260
|
+
onNewConversation=${k}
|
|
261
|
+
onSwitchConversation=${K}
|
|
262
|
+
/>
|
|
263
|
+
`}
|
|
264
|
+
|
|
265
|
+
<${lt}
|
|
266
|
+
config=${e}
|
|
267
|
+
debugMode=${_}
|
|
268
|
+
isExpanded=${l}
|
|
269
|
+
isSpeaking=${w}
|
|
270
|
+
messagesCount=${p.messages.length}
|
|
271
|
+
isLoading=${p.isLoading}
|
|
272
|
+
currentAgent=${A}
|
|
273
|
+
onClose=${()=>o(!1)}
|
|
274
|
+
onToggleExpand=${()=>c(!l)}
|
|
275
|
+
onToggleDebug=${()=>i(!_)}
|
|
276
|
+
onToggleTTS=${()=>g(!b)}
|
|
277
|
+
onClear=${p.clearMessages}
|
|
278
|
+
onToggleSidebar=${I}
|
|
279
|
+
/>
|
|
280
|
+
|
|
281
|
+
${_&&y`<div class="cw-status-bar"><span>🐛 Debug</span></div>`}
|
|
282
|
+
|
|
283
|
+
<${ct}
|
|
284
|
+
messages=${p.messages}
|
|
285
|
+
isLoading=${p.isLoading}
|
|
286
|
+
hasMoreMessages=${p.hasMoreMessages}
|
|
287
|
+
loadingMoreMessages=${p.loadingMoreMessages}
|
|
288
|
+
onLoadMore=${p.loadMoreMessages}
|
|
289
|
+
debugMode=${_}
|
|
290
|
+
markdownParser=${n}
|
|
291
|
+
emptyStateTitle=${e.emptyStateTitle}
|
|
292
|
+
emptyStateMessage=${e.emptyStateMessage}
|
|
293
|
+
/>
|
|
294
|
+
|
|
295
|
+
${p.error&&y`<div class="cw-error-bar">${p.error}</div>`}
|
|
296
|
+
|
|
297
|
+
${e.showModelSelector&&$.availableModels.length>0&&y`
|
|
298
|
+
<${dt}
|
|
299
|
+
availableModels=${$.availableModels}
|
|
300
|
+
selectedModel=${$.selectedModel}
|
|
301
|
+
onSelectModel=${$.selectModel}
|
|
302
|
+
disabled=${p.isLoading}
|
|
303
|
+
/>
|
|
304
|
+
`}
|
|
305
|
+
|
|
306
|
+
<${ut}
|
|
307
|
+
onSend=${B}
|
|
308
|
+
onCancel=${p.cancelRun}
|
|
309
|
+
isLoading=${p.isLoading}
|
|
310
|
+
placeholder=${e.placeholder}
|
|
311
|
+
primaryColor=${e.primaryColor}
|
|
312
|
+
/>
|
|
313
|
+
</div>
|
|
314
|
+
`}var yt={backendUrl:"http://localhost:8000",agentKey:"default-agent",title:"Chat Assistant",subtitle:"How can we help you today?",primaryColor:"#0066cc",position:"bottom-right",defaultJourneyType:"general",enableDebugMode:!0,enableAutoRun:!0,journeyTypes:{},customerPrompts:{},placeholder:"Type your message...",emptyStateTitle:"Start a Conversation",emptyStateMessage:"Send a message to get started.",authStrategy:null,authToken:null,authHeader:null,authTokenPrefix:null,anonymousSessionEndpoint:null,anonymousTokenKey:"chat_widget_anonymous_token",onAuthError:null,anonymousTokenHeader:"X-Anonymous-Token",conversationIdKey:"chat_widget_conversation_id",sessionTokenKey:"chat_widget_session_token",apiPaths:{anonymousSession:"/api/accounts/anonymous-session/",conversations:"/api/agent-runtime/conversations/",runs:"/api/agent-runtime/runs/",runEvents:"/api/agent-runtime/runs/{runId}/events/",simulateCustomer:"/api/agent-runtime/simulate-customer/",ttsVoices:"/api/tts/voices/",ttsSetVoice:"/api/tts/set-voice/",models:"/api/agent-runtime/models/"},showConversationSidebar:!0,showClearButton:!0,showDebugButton:!0,showTTSButton:!0,showVoiceSettings:!0,showExpandButton:!0,showModelSelector:!1,modelKey:"chat_widget_selected_model",autoRunDelay:1e3,autoRunMode:"automatic",enableTTS:!1,ttsProxyUrl:null,elevenLabsApiKey:null,ttsVoices:{assistant:null,user:null},ttsModel:"eleven_turbo_v2_5",ttsSettings:{stability:.5,similarity_boost:.75,style:0,use_speaker_boost:!0},availableVoices:[],onEvent:null,containerId:null,embedded:!1,metadata:{}};function gt(e){let t={...yt.apiPaths,...e.apiPaths||{}};return{...yt,...e,apiPaths:t}}var pe=new Map,Ot=0,T=null,Me=class{constructor(t={}){this.instanceId=`cw-${++Ot}`,this.config=gt(t),this.container=null,this._state={},this._apiRef={current:null},pe.set(this.instanceId,this)}_handleStateChange=t=>{this._state=t};init(){if(this.config.containerId){if(this.container=document.getElementById(this.config.containerId),!this.container)return console.error(`[ChatWidget] Container not found: ${this.config.containerId}`),this;this.container.classList.add("cw-container-embedded")}else this.container=document.createElement("div"),this.container.id=this.instanceId,this.container.className=`cw-container cw-position-${this.config.position}`,document.body.appendChild(this.container);return this._render(),console.log(`[ChatWidget] Instance ${this.instanceId} initialized`),this}_render(t={}){this.container&&ue(y`<${mt}
|
|
315
|
+
config=${{...this.config,...t}}
|
|
316
|
+
onStateChange=${this._handleStateChange}
|
|
317
|
+
markdownParser=${fe._enhancedMarkdownParser}
|
|
318
|
+
apiRef=${this._apiRef}
|
|
319
|
+
/>`,this.container)}destroy(){this.container&&(ue(null,this.container),this.config.containerId?this.container.classList.remove("cw-container-embedded"):this.container.remove(),this.container=null),pe.delete(this.instanceId),console.log(`[ChatWidget] Instance ${this.instanceId} destroyed`)}open(){this._apiRef.current?this._apiRef.current.open():this._render({forceOpen:!0})}close(){this._apiRef.current?this._apiRef.current.close():this._render({forceOpen:!1})}send(t){this._apiRef.current&&this._apiRef.current.send(t)}clearMessages(){this._apiRef.current&&this._apiRef.current.clearMessages()}toggleTTS(){this._apiRef.current&&this._apiRef.current.toggleTTS()}stopSpeech(){this._apiRef.current&&this._apiRef.current.stopSpeech()}setAuth(t){this._apiRef.current&&this._apiRef.current.setAuth(t)}clearAuth(){this._apiRef.current&&this._apiRef.current.clearAuth()}getState(){return{...this._state}}getConfig(){return{...this.config}}};function vt(e={}){return new Me(e).init()}function Rt(e={}){return T&&T.destroy(),T=vt(e),T}function Ut(){T&&(T.destroy(),T=null)}function Ft(){T&&T.open()}function Lt(){T&&T.close()}function Wt(e){T&&T.send(e)}function Kt(){T&&T.clearMessages()}function Bt(){T&&T.toggleTTS()}function jt(){T&&T.stopSpeech()}function Jt(e){T&&T.setAuth(e)}function Vt(){T&&T.clearAuth()}function qt(){return T?T.getState():null}function zt(){return T?T.getConfig():null}var fe={createInstance:vt,getInstance:e=>pe.get(e),getAllInstances:()=>Array.from(pe.values()),init:Rt,destroy:Ut,open:Ft,close:Lt,send:Wt,clearMessages:Kt,toggleTTS:Bt,stopSpeech:jt,setAuth:Jt,clearAuth:Vt,getState:qt,getConfig:zt,_enhancedMarkdownParser:null};var Gt=fe;typeof window<"u"&&(window.ChatWidget=fe);return St(Xt);})();
|