@runtypelabs/persona 1.38.3 → 1.40.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 +174 -2
- package/dist/index.cjs +30 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +135 -11
- package/dist/index.d.ts +135 -11
- package/dist/index.global.js +52 -52
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +30 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client.ts +30 -30
- package/src/components/header-builder.ts +3 -3
- package/src/session.ts +27 -13
- package/src/types.ts +133 -7
- package/src/ui.ts +200 -8
package/README.md
CHANGED
|
@@ -283,9 +283,9 @@ const chat = initAgentWidget({ /* ... */ })
|
|
|
283
283
|
window.chatController = chat
|
|
284
284
|
```
|
|
285
285
|
|
|
286
|
-
### Events
|
|
286
|
+
### DOM Events
|
|
287
287
|
|
|
288
|
-
The widget dispatches custom events that you can listen to for integration with your application:
|
|
288
|
+
The widget dispatches custom DOM events that you can listen to for integration with your application:
|
|
289
289
|
|
|
290
290
|
#### `persona:clear-chat`
|
|
291
291
|
|
|
@@ -309,6 +309,178 @@ window.addEventListener("persona:clear-chat", (event) => {
|
|
|
309
309
|
|
|
310
310
|
**Note:** The widget automatically clears the `"persona-chat-history"` localStorage key by default when chat is cleared. If you set `clearChatHistoryStorageKey` in the config, it will also clear that additional key. You can still listen to this event for additional custom behavior.
|
|
311
311
|
|
|
312
|
+
### Controller Events
|
|
313
|
+
|
|
314
|
+
The widget controller exposes an event system for reacting to chat events. Use `controller.on(eventName, callback)` to subscribe and `controller.off(eventName, callback)` to unsubscribe.
|
|
315
|
+
|
|
316
|
+
#### Available Events
|
|
317
|
+
|
|
318
|
+
| Event | Payload | Description |
|
|
319
|
+
|-------|---------|-------------|
|
|
320
|
+
| `user:message` | `AgentWidgetMessage` | Emitted when a new user message is detected. Includes `viaVoice: true` if sent via voice. |
|
|
321
|
+
| `assistant:message` | `AgentWidgetMessage` | Emitted when an assistant message starts streaming |
|
|
322
|
+
| `assistant:complete` | `AgentWidgetMessage` | Emitted when an assistant message finishes streaming |
|
|
323
|
+
| `voice:state` | `AgentWidgetVoiceStateEvent` | Emitted when voice recognition state changes |
|
|
324
|
+
| `action:detected` | `AgentWidgetActionEventPayload` | Emitted when an action is parsed from an assistant message |
|
|
325
|
+
| `widget:opened` | `AgentWidgetStateEvent` | Emitted when the widget panel opens |
|
|
326
|
+
| `widget:closed` | `AgentWidgetStateEvent` | Emitted when the widget panel closes |
|
|
327
|
+
| `widget:state` | `AgentWidgetStateSnapshot` | Emitted on any widget state change |
|
|
328
|
+
| `message:feedback` | `AgentWidgetMessageFeedback` | Emitted when user provides feedback (upvote/downvote) |
|
|
329
|
+
| `message:copy` | `AgentWidgetMessage` | Emitted when user copies a message |
|
|
330
|
+
|
|
331
|
+
#### Event Payload Types
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
// Voice state event
|
|
335
|
+
type AgentWidgetVoiceStateEvent = {
|
|
336
|
+
active: boolean;
|
|
337
|
+
source: "user" | "auto" | "restore" | "system";
|
|
338
|
+
timestamp: number;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
// Widget state event (for opened/closed)
|
|
342
|
+
type AgentWidgetStateEvent = {
|
|
343
|
+
open: boolean;
|
|
344
|
+
source: "user" | "auto" | "api" | "system";
|
|
345
|
+
timestamp: number;
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// Widget state snapshot
|
|
349
|
+
type AgentWidgetStateSnapshot = {
|
|
350
|
+
open: boolean;
|
|
351
|
+
launcherEnabled: boolean;
|
|
352
|
+
voiceActive: boolean;
|
|
353
|
+
streaming: boolean;
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
// Action event payload
|
|
357
|
+
type AgentWidgetActionEventPayload = {
|
|
358
|
+
action: AgentWidgetParsedAction;
|
|
359
|
+
message: AgentWidgetMessage;
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// Message feedback
|
|
363
|
+
type AgentWidgetMessageFeedback = {
|
|
364
|
+
type: "upvote" | "downvote";
|
|
365
|
+
messageId: string;
|
|
366
|
+
message: AgentWidgetMessage;
|
|
367
|
+
};
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### Example: Listening to Events
|
|
371
|
+
|
|
372
|
+
```ts
|
|
373
|
+
const chat = initAgentWidget({
|
|
374
|
+
target: 'body',
|
|
375
|
+
config: { apiUrl: '/api/chat/dispatch' }
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Listen for new user messages
|
|
379
|
+
chat.on('user:message', (message) => {
|
|
380
|
+
console.log('User sent:', message.content);
|
|
381
|
+
if (message.viaVoice) {
|
|
382
|
+
console.log('Message was sent via voice recognition');
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
// Listen for completed assistant responses
|
|
387
|
+
chat.on('assistant:complete', (message) => {
|
|
388
|
+
console.log('Assistant replied:', message.content);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
// Listen for voice state changes
|
|
392
|
+
chat.on('voice:state', (event) => {
|
|
393
|
+
console.log('Voice active:', event.active, 'Source:', event.source);
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
// Listen for widget open/close
|
|
397
|
+
chat.on('widget:opened', (event) => {
|
|
398
|
+
console.log('Widget opened by:', event.source);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
chat.on('widget:closed', (event) => {
|
|
402
|
+
console.log('Widget closed by:', event.source);
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Listen for parsed actions from assistant messages
|
|
406
|
+
chat.on('action:detected', ({ action, message }) => {
|
|
407
|
+
console.log('Action detected:', action.type, action.payload);
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
#### Example: Voice Mode Persistence
|
|
412
|
+
|
|
413
|
+
The `user:message` event is useful for implementing custom voice mode persistence across page navigations:
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
const chat = initAgentWidget({
|
|
417
|
+
target: 'body',
|
|
418
|
+
config: {
|
|
419
|
+
apiUrl: '/api/chat/dispatch',
|
|
420
|
+
voiceRecognition: { enabled: true }
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Track if the user is in "voice mode"
|
|
425
|
+
chat.on('user:message', (message) => {
|
|
426
|
+
localStorage.setItem('voice-mode', message.viaVoice ? 'true' : 'false');
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// On page load, restore voice mode if the user was using voice
|
|
430
|
+
if (localStorage.getItem('voice-mode') === 'true') {
|
|
431
|
+
chat.startVoiceRecognition();
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Note: The built-in `persistState` option handles this automatically when configured:
|
|
436
|
+
|
|
437
|
+
```ts
|
|
438
|
+
initAgentWidget({
|
|
439
|
+
target: 'body',
|
|
440
|
+
config: {
|
|
441
|
+
persistState: true, // Automatically persists open state and voice mode
|
|
442
|
+
voiceRecognition: { enabled: true, autoResume: 'assistant' }
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### State Loaded Hook
|
|
448
|
+
|
|
449
|
+
The `onStateLoaded` hook is called after state is loaded from the storage adapter, but before the widget initializes. Use this to transform or inject messages based on external state (e.g., navigation flags, checkout returns).
|
|
450
|
+
|
|
451
|
+
```ts
|
|
452
|
+
initAgentWidget({
|
|
453
|
+
target: 'body',
|
|
454
|
+
config: {
|
|
455
|
+
storageAdapter: createLocalStorageAdapter('my-chat'),
|
|
456
|
+
onStateLoaded: (state) => {
|
|
457
|
+
// Check for pending navigation message
|
|
458
|
+
const navMessage = consumeNavigationFlag();
|
|
459
|
+
if (navMessage) {
|
|
460
|
+
return {
|
|
461
|
+
...state,
|
|
462
|
+
messages: [...(state.messages || []), {
|
|
463
|
+
id: `nav-${Date.now()}`,
|
|
464
|
+
role: 'assistant',
|
|
465
|
+
content: navMessage,
|
|
466
|
+
createdAt: new Date().toISOString()
|
|
467
|
+
}]
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
return state;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
**Use cases:**
|
|
477
|
+
- Inject messages after page navigation (e.g., "Here are our products!")
|
|
478
|
+
- Add confirmation messages after checkout/payment returns
|
|
479
|
+
- Transform or filter loaded messages
|
|
480
|
+
- Inject system messages based on external state
|
|
481
|
+
|
|
482
|
+
The hook receives the loaded state and must return the (potentially modified) state synchronously.
|
|
483
|
+
|
|
312
484
|
### Message Actions (Copy, Upvote, Downvote)
|
|
313
485
|
|
|
314
486
|
The widget includes built-in action buttons for assistant messages that allow users to copy message content and provide feedback through upvote/downvote buttons.
|