@makemore/agent-frontend 1.6.0 → 1.7.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/README.md +35 -0
- package/dist/chat-widget.js +82 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -174,6 +174,41 @@ See `django-tts-example.py` for the complete Django backend implementation.
|
|
|
174
174
|
| `showTTSButton` | boolean | `true` | Show TTS toggle button in header |
|
|
175
175
|
| `showVoiceSettings` | boolean | `true` | Show voice settings button in header (works with proxy and direct API) |
|
|
176
176
|
| `showExpandButton` | boolean | `true` | Show expand/minimize button in header |
|
|
177
|
+
| `onEvent` | function | `null` | Callback for SSE events: `(eventType, payload) => void` |
|
|
178
|
+
|
|
179
|
+
### Event Callback
|
|
180
|
+
|
|
181
|
+
The `onEvent` callback allows your application to react to all SSE events from the agent:
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
ChatWidget.init({
|
|
185
|
+
backendUrl: 'http://localhost:8000',
|
|
186
|
+
agentKey: 'your-agent',
|
|
187
|
+
onEvent: (eventType, payload) => {
|
|
188
|
+
console.log('Event:', eventType, payload);
|
|
189
|
+
|
|
190
|
+
// Example: Navigate when a session is created
|
|
191
|
+
if (eventType === 'tool.result' && payload.result?.session_id) {
|
|
192
|
+
window.location.href = `/session/${payload.result.session_id}`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Example: Track tool usage
|
|
196
|
+
if (eventType === 'tool.call') {
|
|
197
|
+
analytics.track('Tool Called', { tool: payload.name });
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
**Event Types:**
|
|
204
|
+
- `assistant.message` - Streaming assistant responses (payload: `{ content: string }`)
|
|
205
|
+
- `tool.call` - Tool being called (payload: `{ name: string, arguments: object }`)
|
|
206
|
+
- `tool.result` - Tool result (payload: `{ result: any }`)
|
|
207
|
+
- `run.succeeded` - Run completed successfully
|
|
208
|
+
- `run.failed` - Run failed (payload: `{ error: string }`)
|
|
209
|
+
- `run.cancelled` - Run was cancelled
|
|
210
|
+
- `run.timed_out` - Run timed out
|
|
211
|
+
- Custom events emitted by your agent
|
|
177
212
|
|
|
178
213
|
### Text-to-Speech (ElevenLabs)
|
|
179
214
|
|
package/dist/chat-widget.js
CHANGED
|
@@ -70,6 +70,8 @@
|
|
|
70
70
|
showTTSButton: true,
|
|
71
71
|
showVoiceSettings: true,
|
|
72
72
|
showExpandButton: true,
|
|
73
|
+
// Event callback
|
|
74
|
+
onEvent: null, // Callback for SSE events: (eventType, payload) => void
|
|
73
75
|
};
|
|
74
76
|
|
|
75
77
|
// State
|
|
@@ -492,6 +494,12 @@
|
|
|
492
494
|
eventSource.addEventListener('assistant.message', (event) => {
|
|
493
495
|
try {
|
|
494
496
|
const data = JSON.parse(event.data);
|
|
497
|
+
|
|
498
|
+
// Call onEvent callback if provided
|
|
499
|
+
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
500
|
+
config.onEvent('assistant.message', data.payload);
|
|
501
|
+
}
|
|
502
|
+
|
|
495
503
|
const content = data.payload.content;
|
|
496
504
|
if (content) {
|
|
497
505
|
assistantContent += content;
|
|
@@ -518,18 +526,25 @@
|
|
|
518
526
|
|
|
519
527
|
// Handler for tool calls (debug mode)
|
|
520
528
|
eventSource.addEventListener('tool.call', (event) => {
|
|
521
|
-
if (!state.debugMode) return;
|
|
522
529
|
try {
|
|
523
530
|
const data = JSON.parse(event.data);
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
531
|
+
|
|
532
|
+
// Call onEvent callback if provided
|
|
533
|
+
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
534
|
+
config.onEvent('tool.call', data.payload);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (state.debugMode) {
|
|
538
|
+
state.messages.push({
|
|
539
|
+
id: 'tool-call-' + Date.now(),
|
|
540
|
+
role: 'system',
|
|
541
|
+
content: `🔧 Tool: ${data.payload.name}`,
|
|
542
|
+
timestamp: new Date(),
|
|
543
|
+
type: 'tool_call',
|
|
544
|
+
metadata: { name: data.payload.name, arguments: data.payload.arguments },
|
|
545
|
+
});
|
|
546
|
+
render();
|
|
547
|
+
}
|
|
533
548
|
} catch (err) {
|
|
534
549
|
console.error('[ChatWidget] Failed to parse tool.call:', err);
|
|
535
550
|
}
|
|
@@ -537,19 +552,26 @@
|
|
|
537
552
|
|
|
538
553
|
// Handler for tool results (debug mode)
|
|
539
554
|
eventSource.addEventListener('tool.result', (event) => {
|
|
540
|
-
if (!state.debugMode) return;
|
|
541
555
|
try {
|
|
542
556
|
const data = JSON.parse(event.data);
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
557
|
+
|
|
558
|
+
// Call onEvent callback if provided
|
|
559
|
+
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
560
|
+
config.onEvent('tool.result', data.payload);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (state.debugMode) {
|
|
564
|
+
const result = data.payload.result || '';
|
|
565
|
+
state.messages.push({
|
|
566
|
+
id: 'tool-result-' + Date.now(),
|
|
567
|
+
role: 'system',
|
|
568
|
+
content: `✅ Result: ${result.substring(0, 100)}${result.length > 100 ? '...' : ''}`,
|
|
569
|
+
timestamp: new Date(),
|
|
570
|
+
type: 'tool_result',
|
|
571
|
+
metadata: { result },
|
|
572
|
+
});
|
|
573
|
+
render();
|
|
574
|
+
}
|
|
553
575
|
} catch (err) {
|
|
554
576
|
console.error('[ChatWidget] Failed to parse tool.result:', err);
|
|
555
577
|
}
|
|
@@ -559,6 +581,12 @@
|
|
|
559
581
|
const handleTerminal = (event) => {
|
|
560
582
|
try {
|
|
561
583
|
const data = JSON.parse(event.data);
|
|
584
|
+
|
|
585
|
+
// Call onEvent callback if provided
|
|
586
|
+
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
587
|
+
config.onEvent(data.type, data.payload);
|
|
588
|
+
}
|
|
589
|
+
|
|
562
590
|
if (data.type === 'run.failed') {
|
|
563
591
|
state.error = data.payload.error || 'Agent run failed';
|
|
564
592
|
state.messages.push({
|
|
@@ -604,6 +632,22 @@
|
|
|
604
632
|
eventSource.addEventListener('run.cancelled', handleTerminal);
|
|
605
633
|
eventSource.addEventListener('run.timed_out', handleTerminal);
|
|
606
634
|
|
|
635
|
+
// Generic handler for any other custom events
|
|
636
|
+
eventSource.onmessage = (event) => {
|
|
637
|
+
try {
|
|
638
|
+
const data = JSON.parse(event.data);
|
|
639
|
+
|
|
640
|
+
// Call onEvent callback for any unhandled events
|
|
641
|
+
if (config.onEvent && typeof config.onEvent === 'function') {
|
|
642
|
+
// Extract event type from data or use 'message' as default
|
|
643
|
+
const eventType = data.type || 'message';
|
|
644
|
+
config.onEvent(eventType, data.payload || data);
|
|
645
|
+
}
|
|
646
|
+
} catch (err) {
|
|
647
|
+
console.debug('[ChatWidget] Received non-JSON SSE message:', event.data);
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
|
|
607
651
|
eventSource.onerror = () => {
|
|
608
652
|
if (eventSource.readyState !== EventSource.CLOSED) {
|
|
609
653
|
console.debug('[ChatWidget] SSE connection closed');
|
|
@@ -645,7 +689,7 @@
|
|
|
645
689
|
state.isSimulating = false;
|
|
646
690
|
|
|
647
691
|
// Speak simulated user message if TTS enabled
|
|
648
|
-
if (config.enableTTS
|
|
692
|
+
if (config.enableTTS) {
|
|
649
693
|
await speakText(data.response, 'user');
|
|
650
694
|
}
|
|
651
695
|
|
|
@@ -670,9 +714,15 @@
|
|
|
670
714
|
|
|
671
715
|
const journey = config.journeyTypes[journeyType];
|
|
672
716
|
if (journey?.initialMessage) {
|
|
673
|
-
setTimeout(() => {
|
|
717
|
+
setTimeout(async () => {
|
|
674
718
|
state.isSimulating = true;
|
|
675
719
|
render();
|
|
720
|
+
|
|
721
|
+
// Speak initial message if TTS enabled
|
|
722
|
+
if (config.enableTTS) {
|
|
723
|
+
await speakText(journey.initialMessage, 'user');
|
|
724
|
+
}
|
|
725
|
+
|
|
676
726
|
sendMessage(journey.initialMessage).then(() => {
|
|
677
727
|
state.isSimulating = false;
|
|
678
728
|
render();
|
|
@@ -1009,6 +1059,13 @@
|
|
|
1009
1059
|
if (messagesEl) {
|
|
1010
1060
|
messagesEl.scrollTop = messagesEl.scrollHeight;
|
|
1011
1061
|
}
|
|
1062
|
+
|
|
1063
|
+
// Focus input field
|
|
1064
|
+
const inputEl = container.querySelector('.cw-input');
|
|
1065
|
+
if (inputEl && !state.isLoading) {
|
|
1066
|
+
// Use setTimeout to ensure focus happens after render completes
|
|
1067
|
+
setTimeout(() => inputEl.focus(), 0);
|
|
1068
|
+
}
|
|
1012
1069
|
}
|
|
1013
1070
|
|
|
1014
1071
|
function attachEventListeners() {
|
|
@@ -1058,6 +1115,8 @@
|
|
|
1058
1115
|
if (input && input.value.trim()) {
|
|
1059
1116
|
sendMessage(input.value);
|
|
1060
1117
|
input.value = '';
|
|
1118
|
+
// Keep focus on input after sending
|
|
1119
|
+
input.focus();
|
|
1061
1120
|
}
|
|
1062
1121
|
});
|
|
1063
1122
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@makemore/agent-frontend",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "A standalone, zero-dependency chat widget for AI agents. Embed conversational AI into any website with a single script tag.",
|
|
5
5
|
"main": "dist/chat-widget.js",
|
|
6
6
|
"files": [
|