vanilla-agent 1.3.0 → 1.4.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 +219 -3
- package/dist/index.cjs +7 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +131 -1
- package/dist/index.d.ts +131 -1
- package/dist/index.global.js +51 -48
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/widget.css +21 -0
- package/package.json +4 -2
- package/src/client.test.ts +197 -0
- package/src/client.ts +330 -15
- package/src/components/forms.ts +2 -0
- package/src/components/message-bubble.ts +9 -4
- package/src/components/messages.ts +5 -3
- package/src/components/panel.ts +1 -0
- package/src/components/reasoning-bubble.ts +26 -8
- package/src/components/tool-bubble.ts +139 -22
- package/src/index.ts +9 -1
- package/src/plugins/registry.ts +2 -0
- package/src/plugins/types.ts +2 -0
- package/src/runtime/init.ts +4 -1
- package/src/session.ts +4 -0
- package/src/styles/widget.css +21 -0
- package/src/types.ts +107 -0
- package/src/ui.ts +145 -5
- package/src/utils/constants.ts +2 -0
- package/src/utils/dom.ts +2 -0
- package/src/utils/formatting.test.ts +160 -0
- package/src/utils/formatting.ts +252 -1
- package/src/utils/positioning.ts +2 -0
- package/src/utils/theme.ts +2 -0
package/README.md
CHANGED
|
@@ -129,6 +129,18 @@ chat.stopVoiceRecognition()
|
|
|
129
129
|
|
|
130
130
|
All hook methods return `boolean` indicating success (`true`) or failure (`false`). They will automatically open the widget if it's currently closed (when launcher is enabled).
|
|
131
131
|
|
|
132
|
+
#### Clear chat
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
const chat = initAgentWidget({
|
|
136
|
+
target: '#launcher-root',
|
|
137
|
+
config: { /* ... */ }
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
// Clear all messages programmatically
|
|
141
|
+
chat.clearChat()
|
|
142
|
+
```
|
|
143
|
+
|
|
132
144
|
#### Accessing from window
|
|
133
145
|
|
|
134
146
|
To access the controller globally (e.g., from browser console or external scripts), use the `windowKey` option:
|
|
@@ -184,6 +196,32 @@ const chat = initAgentWidget({ /* ... */ })
|
|
|
184
196
|
window.chatController = chat
|
|
185
197
|
```
|
|
186
198
|
|
|
199
|
+
### Events
|
|
200
|
+
|
|
201
|
+
The widget dispatches custom events that you can listen to for integration with your application:
|
|
202
|
+
|
|
203
|
+
#### `vanilla-agent:clear-chat`
|
|
204
|
+
|
|
205
|
+
Dispatched when the user clicks the "Clear chat" button or when `chat.clearChat()` is called programmatically.
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
window.addEventListener("vanilla-agent:clear-chat", (event) => {
|
|
209
|
+
console.log("Chat cleared at:", event.detail.timestamp);
|
|
210
|
+
// Clear your localStorage, reset state, etc.
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
**Event detail:**
|
|
215
|
+
- `timestamp`: ISO timestamp string of when the chat was cleared
|
|
216
|
+
|
|
217
|
+
**Use cases:**
|
|
218
|
+
- Clear localStorage chat history
|
|
219
|
+
- Reset application state
|
|
220
|
+
- Track analytics events
|
|
221
|
+
- Sync with backend
|
|
222
|
+
|
|
223
|
+
**Note:** The widget automatically clears the `"vanilla-agent-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.
|
|
224
|
+
|
|
187
225
|
### Travrse adapter
|
|
188
226
|
|
|
189
227
|
This package ships with a Travrse adapter by default. The proxy handles all flow configuration, keeping the client lightweight and flexible.
|
|
@@ -228,7 +266,9 @@ The easiest way is to use the automatic installer script. It handles loading CSS
|
|
|
228
266
|
theme: {
|
|
229
267
|
accent: '#2563eb',
|
|
230
268
|
surface: '#ffffff'
|
|
231
|
-
}
|
|
269
|
+
},
|
|
270
|
+
// Optional: configure stream parser for JSON/XML responses
|
|
271
|
+
// streamParser: () => window.AgentWidget.createJsonStreamParser()
|
|
232
272
|
}
|
|
233
273
|
};
|
|
234
274
|
</script>
|
|
@@ -286,7 +326,9 @@ For more control, manually load CSS and JavaScript:
|
|
|
286
326
|
theme: {
|
|
287
327
|
accent: '#111827',
|
|
288
328
|
surface: '#f5f5f5'
|
|
289
|
-
}
|
|
329
|
+
},
|
|
330
|
+
// Optional: configure stream parser for JSON/XML responses
|
|
331
|
+
streamParser: window.AgentWidget.createJsonStreamParser // or createXmlParser, createPlainTextParser
|
|
290
332
|
}
|
|
291
333
|
});
|
|
292
334
|
|
|
@@ -308,7 +350,14 @@ Replace `VERSION` with `latest` for auto-updates, or a specific version like `0.
|
|
|
308
350
|
- `index.global.js` - Widget JavaScript (IIFE format)
|
|
309
351
|
- `install.global.js` - Automatic installer script
|
|
310
352
|
|
|
311
|
-
The script build exposes a `window.AgentWidget` global with `initAgentWidget()` and other exports
|
|
353
|
+
The script build exposes a `window.AgentWidget` global with `initAgentWidget()` and other exports, including parser functions:
|
|
354
|
+
|
|
355
|
+
- `window.AgentWidget.initAgentWidget()` - Initialize the widget
|
|
356
|
+
- `window.AgentWidget.createPlainTextParser()` - Plain text parser (default)
|
|
357
|
+
- `window.AgentWidget.createJsonStreamParser()` - JSON parser using schema-stream
|
|
358
|
+
- `window.AgentWidget.createXmlParser()` - XML parser
|
|
359
|
+
- `window.AgentWidget.markdownPostprocessor()` - Markdown postprocessor
|
|
360
|
+
- `window.AgentWidget.directivePostprocessor()` - Directive postprocessor
|
|
312
361
|
|
|
313
362
|
### Using default configuration
|
|
314
363
|
|
|
@@ -356,12 +405,179 @@ This ensures all configuration values are set to sensible defaults while allowin
|
|
|
356
405
|
| `initialMessages` | `AgentWidgetMessage[]` | Seed the conversation transcript. |
|
|
357
406
|
| `suggestionChips` | `string[]` | Render quick reply buttons above the composer. |
|
|
358
407
|
| `postprocessMessage` | `(ctx) => string` | Transform message text before it renders (return HTML). Combine with `markdownPostprocessor` for rich output. |
|
|
408
|
+
| `streamParser` | `() => AgentWidgetStreamParser` | Custom stream parser for detecting formats and extracting text from streaming responses. Handles JSON, XML, or custom formats. See [Stream Parser Configuration](#stream-parser-configuration) below. |
|
|
409
|
+
| `clearChatHistoryStorageKey` | `string` | Additional localStorage key to clear when the clear chat button is clicked. The widget automatically clears `"vanilla-agent-chat-history"` by default. Use this option to clear additional keys (e.g., if you're using a custom storage key). |
|
|
359
410
|
| `formEndpoint` | `string` | Endpoint used by built-in directives (defaults to `/form`). |
|
|
360
411
|
| `launcherWidth` | `string` | CSS width applied to the floating launcher panel (e.g. `320px`, `90vw`). Defaults to `min(400px, calc(100vw - 24px))`. |
|
|
361
412
|
| `debug` | `boolean` | Emits verbose logs to `console`. |
|
|
362
413
|
|
|
363
414
|
All options are safe to mutate via `initAgentWidget(...).update(newConfig)`.
|
|
364
415
|
|
|
416
|
+
### Stream Parser Configuration
|
|
417
|
+
|
|
418
|
+
The widget can parse structured responses (JSON, XML, etc.) that stream in chunk by chunk, extracting the `text` field for display. By default, it uses a schema-stream based JSON parser. You can provide a custom parser to handle different formats, structures, or parsing strategies.
|
|
419
|
+
|
|
420
|
+
**Key benefits of the unified stream parser:**
|
|
421
|
+
- **Format detection**: Automatically detects if content matches your parser's format
|
|
422
|
+
- **Extensible**: Handle JSON, XML, or any custom structured format
|
|
423
|
+
- **Incremental parsing**: Extract text as it streams in, not just when complete
|
|
424
|
+
|
|
425
|
+
**Using built-in parsers with ESM/Modules:**
|
|
426
|
+
|
|
427
|
+
```javascript
|
|
428
|
+
import { initAgentWidget, createPlainTextParser, createJsonStreamParser, createXmlParser } from 'vanilla-agent';
|
|
429
|
+
|
|
430
|
+
const controller = initAgentWidget({
|
|
431
|
+
target: '#chat-root',
|
|
432
|
+
config: {
|
|
433
|
+
apiUrl: '/api/chat/dispatch',
|
|
434
|
+
streamParser: createJsonStreamParser // Use JSON parser
|
|
435
|
+
// Or: createXmlParser for XML, createPlainTextParser for plain text (default)
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Using built-in parsers with CDN Script Tags:**
|
|
441
|
+
|
|
442
|
+
```html
|
|
443
|
+
<script src="https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist/index.global.js"></script>
|
|
444
|
+
<script>
|
|
445
|
+
window.AgentWidget.initAgentWidget({
|
|
446
|
+
target: '#chat-root',
|
|
447
|
+
config: {
|
|
448
|
+
apiUrl: '/api/chat/dispatch',
|
|
449
|
+
streamParser: window.AgentWidget.createJsonStreamParser // JSON parser
|
|
450
|
+
// Or: window.AgentWidget.createXmlParser for XML
|
|
451
|
+
// Or: window.AgentWidget.createPlainTextParser for plain text (default)
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
</script>
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
**Using with automatic installer script:**
|
|
458
|
+
|
|
459
|
+
```html
|
|
460
|
+
<script>
|
|
461
|
+
window.siteAgentConfig = {
|
|
462
|
+
target: 'body',
|
|
463
|
+
config: {
|
|
464
|
+
apiUrl: '/api/chat/dispatch',
|
|
465
|
+
// Note: streamParser must be set after the script loads, or use a function
|
|
466
|
+
streamParser: function() {
|
|
467
|
+
return window.AgentWidget.createJsonStreamParser();
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
</script>
|
|
472
|
+
<script src="https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist/install.global.js"></script>
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Alternatively, you can set it after the script loads:
|
|
476
|
+
|
|
477
|
+
```html
|
|
478
|
+
<script>
|
|
479
|
+
window.siteAgentConfig = {
|
|
480
|
+
target: 'body',
|
|
481
|
+
config: {
|
|
482
|
+
apiUrl: '/api/chat/dispatch'
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
</script>
|
|
486
|
+
<script src="https://cdn.jsdelivr.net/npm/vanilla-agent@latest/dist/install.global.js"></script>
|
|
487
|
+
<script>
|
|
488
|
+
// Set parser after AgentWidget is loaded
|
|
489
|
+
if (window.siteAgentConfig && window.AgentWidget) {
|
|
490
|
+
window.siteAgentConfig.config.streamParser = window.AgentWidget.createJsonStreamParser;
|
|
491
|
+
}
|
|
492
|
+
</script>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
**Custom JSON parser example:**
|
|
496
|
+
|
|
497
|
+
```javascript
|
|
498
|
+
const jsonParser = () => {
|
|
499
|
+
let extractedText = null;
|
|
500
|
+
|
|
501
|
+
return {
|
|
502
|
+
// Extract text field from JSON as it streams in
|
|
503
|
+
// Return null if not JSON or text not available yet
|
|
504
|
+
processChunk(accumulatedContent) {
|
|
505
|
+
const trimmed = accumulatedContent.trim();
|
|
506
|
+
// Return null if not JSON format
|
|
507
|
+
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const match = accumulatedContent.match(/"text"\s*:\s*"([^"]*(?:\\.[^"]*)*)"/);
|
|
512
|
+
if (match) {
|
|
513
|
+
extractedText = match[1].replace(/\\"/g, '"').replace(/\\n/g, '\n');
|
|
514
|
+
return extractedText;
|
|
515
|
+
}
|
|
516
|
+
return null;
|
|
517
|
+
},
|
|
518
|
+
|
|
519
|
+
getExtractedText() {
|
|
520
|
+
return extractedText;
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
const controller = initAgentWidget({
|
|
526
|
+
target: '#chat-root',
|
|
527
|
+
config: {
|
|
528
|
+
apiUrl: '/api/chat/dispatch',
|
|
529
|
+
streamParser: jsonParser
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Custom XML parser example:**
|
|
535
|
+
|
|
536
|
+
```javascript
|
|
537
|
+
const xmlParser = () => {
|
|
538
|
+
let extractedText = null;
|
|
539
|
+
|
|
540
|
+
return {
|
|
541
|
+
processChunk(accumulatedContent) {
|
|
542
|
+
// Return null if not XML format
|
|
543
|
+
if (!accumulatedContent.trim().startsWith('<')) {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Extract text from <text>...</text> tags
|
|
548
|
+
const match = accumulatedContent.match(/<text[^>]*>([\s\S]*?)<\/text>/);
|
|
549
|
+
if (match) {
|
|
550
|
+
extractedText = match[1];
|
|
551
|
+
return extractedText;
|
|
552
|
+
}
|
|
553
|
+
return null;
|
|
554
|
+
},
|
|
555
|
+
|
|
556
|
+
getExtractedText() {
|
|
557
|
+
return extractedText;
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
};
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
**Parser interface:**
|
|
564
|
+
|
|
565
|
+
```typescript
|
|
566
|
+
interface AgentWidgetStreamParser {
|
|
567
|
+
// Process a chunk and return extracted text (if available)
|
|
568
|
+
// Return null if the content doesn't match this parser's format or text is not yet available
|
|
569
|
+
processChunk(accumulatedContent: string): Promise<string | null> | string | null;
|
|
570
|
+
|
|
571
|
+
// Get the currently extracted text (may be partial)
|
|
572
|
+
getExtractedText(): string | null;
|
|
573
|
+
|
|
574
|
+
// Optional cleanup when parsing is complete
|
|
575
|
+
close?(): Promise<void> | void;
|
|
576
|
+
}
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
The parser's `processChunk` method is called for each chunk. If the content matches your parser's format, return the extracted text. If it doesn't match (or text isn't available yet), return `null` and the content will be treated as plain text. This allows you to display the text value as it streams in without showing raw structured characters.
|
|
580
|
+
|
|
365
581
|
### Optional proxy server
|
|
366
582
|
|
|
367
583
|
The proxy server handles flow configuration and forwards requests to Travrse. You can configure it in three ways:
|