@makemore/agent-frontend 1.1.0 → 1.3.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 CHANGED
@@ -61,6 +61,28 @@ Then include in your HTML:
61
61
  <script src="https://cdn.jsdelivr.net/npm/@makemore/agent-frontend/dist/chat-widget.js"></script>
62
62
  ```
63
63
 
64
+ ### Optional: Enhanced Markdown Support
65
+
66
+ For full-featured markdown rendering (tables, code blocks with syntax highlighting, etc.), include the optional markdown addon:
67
+
68
+ ```html
69
+ <!-- Core widget -->
70
+ <link rel="stylesheet" href="https://unpkg.com/@makemore/agent-frontend/dist/chat-widget.css">
71
+ <script src="https://unpkg.com/@makemore/agent-frontend/dist/chat-widget.js"></script>
72
+
73
+ <!-- Optional: Enhanced markdown with marked.js -->
74
+ <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
75
+ <script src="https://unpkg.com/@makemore/agent-frontend/dist/chat-widget-markdown.js"></script>
76
+
77
+ <!-- Optional: Syntax highlighting for code blocks -->
78
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11/styles/github-dark.min.css">
79
+ <script src="https://cdn.jsdelivr.net/npm/highlight.js@11/lib/core.min.js"></script>
80
+ <script src="https://cdn.jsdelivr.net/npm/highlight.js@11/lib/languages/javascript.min.js"></script>
81
+ <script src="https://cdn.jsdelivr.net/npm/highlight.js@11/lib/languages/python.min.js"></script>
82
+ ```
83
+
84
+ The widget automatically detects and uses the enhanced markdown parser if available. Without it, a basic markdown parser is used.
85
+
64
86
  ## Quick Start
65
87
 
66
88
  ### Initialize the widget
@@ -115,6 +137,29 @@ Then include in your HTML:
115
137
  | `conversationIdKey` | string | `'chat_widget_conversation_id'` | localStorage key for conversation ID |
116
138
  | `sessionTokenKey` | string | `'chat_widget_session_token'` | localStorage key for session token |
117
139
  | `apiPaths` | object | See below | API endpoint paths (customizable for different backends) |
140
+ | `autoRunMode` | string | `'automatic'` | Demo flow mode: `'automatic'`, `'confirm'`, or `'manual'` |
141
+ | `autoRunDelay` | number | `1000` | Delay in milliseconds before auto-generating next message (automatic mode) |
142
+
143
+ ### Demo Flow Control
144
+
145
+ The widget supports three modes for demo flows:
146
+
147
+ - **Automatic** (`autoRunMode: 'automatic'`): Continuously generates customer responses with a configurable delay
148
+ - **Confirm Next** (`autoRunMode: 'confirm'`): Pauses after each assistant response and waits for user to click "Continue"
149
+ - **Manual** (`autoRunMode: 'manual'`): Stops auto-generation; user must manually type responses
150
+
151
+ These settings can be changed in real-time via the demo controls dropdown (visible when a demo is running).
152
+
153
+ ```javascript
154
+ ChatWidget.init({
155
+ autoRunMode: 'confirm', // Start in confirm mode
156
+ autoRunDelay: 2000, // 2 second delay in automatic mode
157
+ });
158
+
159
+ // Change mode programmatically
160
+ ChatWidget.setAutoRunMode('automatic');
161
+ ChatWidget.setAutoRunDelay(500); // 0.5 second delay
162
+ ```
118
163
 
119
164
  ### API Paths Configuration
120
165
 
@@ -191,9 +236,18 @@ ChatWidget.clearMessages();
191
236
  // Start a demo flow
192
237
  ChatWidget.startDemoFlow('quote');
193
238
 
194
- // Stop auto-run mode
239
+ // Stop demo flow
195
240
  ChatWidget.stopAutoRun();
196
241
 
242
+ // Continue demo flow (when in confirm mode and paused)
243
+ ChatWidget.continueAutoRun();
244
+
245
+ // Change demo flow mode
246
+ ChatWidget.setAutoRunMode('automatic'); // 'automatic', 'confirm', or 'manual'
247
+
248
+ // Change auto-run delay (in milliseconds)
249
+ ChatWidget.setAutoRunDelay(2000);
250
+
197
251
  // Remove the widget from the page
198
252
  ChatWidget.destroy();
199
253
 
@@ -204,6 +258,34 @@ const state = ChatWidget.getState();
204
258
  const config = ChatWidget.getConfig();
205
259
  ```
206
260
 
261
+ ## Markdown Support
262
+
263
+ The widget includes built-in markdown rendering for assistant messages:
264
+
265
+ ### Basic Markdown (Built-in)
266
+
267
+ The widget includes a lightweight markdown parser that supports:
268
+ - **Bold** (`**text**` or `__text__`)
269
+ - *Italic* (`*text*` or `_text_`)
270
+ - `Inline code` (`` `code` ``)
271
+ - [Links](url) (`[text](url)`)
272
+ - Lists (`- item` or `* item`)
273
+ - Line breaks
274
+
275
+ ### Enhanced Markdown (Optional)
276
+
277
+ Include `chat-widget-markdown.js` for full-featured markdown:
278
+ - **Tables** - Full GFM table support
279
+ - **Code blocks** - Multi-line code with syntax highlighting
280
+ - **Blockquotes** - `> quoted text`
281
+ - **Headings** - `# H1` through `###### H6`
282
+ - **Horizontal rules** - `---` or `***`
283
+ - **Task lists** - `- [ ] todo` and `- [x] done`
284
+ - **Strikethrough** - `~~text~~`
285
+
286
+ **Supported languages for syntax highlighting:**
287
+ Add highlight.js language modules as needed (JavaScript, Python, TypeScript, Go, Rust, etc.)
288
+
207
289
  ## Backend Requirements
208
290
 
209
291
  The widget expects a backend API with the following endpoints:
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Chat Widget - Enhanced Markdown Support
3
+ *
4
+ * This optional addon replaces the basic markdown parser with marked.js
5
+ * for full-featured markdown rendering including tables, code blocks with
6
+ * syntax highlighting, and more.
7
+ *
8
+ * Usage:
9
+ * 1. Include marked.js (and optionally highlight.js for syntax highlighting)
10
+ * 2. Include this file AFTER chat-widget.js
11
+ * 3. Initialize the widget normally
12
+ *
13
+ * Example:
14
+ * <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
15
+ * <script src="https://cdn.jsdelivr.net/npm/highlight.js@11/lib/core.min.js"></script>
16
+ * <script src="https://cdn.jsdelivr.net/npm/highlight.js@11/lib/languages/javascript.min.js"></script>
17
+ * <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@11/styles/github-dark.min.css">
18
+ * <script src="chat-widget.js"></script>
19
+ * <script src="chat-widget-markdown.js"></script>
20
+ */
21
+ (function(global) {
22
+ 'use strict';
23
+
24
+ // Check if ChatWidget is available
25
+ if (!global.ChatWidget) {
26
+ console.error('[ChatWidget Markdown] ChatWidget must be loaded before chat-widget-markdown.js');
27
+ return;
28
+ }
29
+
30
+ // Check if marked is available
31
+ if (typeof marked === 'undefined') {
32
+ console.warn('[ChatWidget Markdown] marked.js not found. Install with: npm install marked or include from CDN');
33
+ console.warn('[ChatWidget Markdown] Falling back to basic markdown parser');
34
+ return;
35
+ }
36
+
37
+ console.log('[ChatWidget Markdown] Enhanced markdown support enabled');
38
+
39
+ // Configure marked
40
+ const markedOptions = {
41
+ breaks: true,
42
+ gfm: true,
43
+ headerIds: false,
44
+ mangle: false,
45
+ };
46
+
47
+ // Configure syntax highlighting if highlight.js is available
48
+ if (typeof hljs !== 'undefined') {
49
+ console.log('[ChatWidget Markdown] Syntax highlighting enabled');
50
+ markedOptions.highlight = function(code, lang) {
51
+ if (lang && hljs.getLanguage(lang)) {
52
+ try {
53
+ return hljs.highlight(code, { language: lang }).value;
54
+ } catch (err) {
55
+ console.error('[ChatWidget Markdown] Highlight error:', err);
56
+ }
57
+ }
58
+ return code;
59
+ };
60
+ }
61
+
62
+ marked.setOptions(markedOptions);
63
+
64
+ // Enhanced markdown parser using marked.js
65
+ function enhancedParseMarkdown(text) {
66
+ if (!text) return '';
67
+
68
+ try {
69
+ // Parse markdown with marked
70
+ let html = marked.parse(text);
71
+
72
+ // Sanitize links to open in new tab
73
+ html = html.replace(/<a href=/g, '<a target="_blank" rel="noopener noreferrer" href=');
74
+
75
+ return html;
76
+ } catch (err) {
77
+ console.error('[ChatWidget Markdown] Parse error:', err);
78
+ // Fallback to escaped text
79
+ const div = document.createElement('div');
80
+ div.textContent = text;
81
+ return div.innerHTML.replace(/\n/g, '<br>');
82
+ }
83
+ }
84
+
85
+ // Store reference to original init
86
+ const originalInit = global.ChatWidget.init;
87
+
88
+ // Override init to inject enhanced markdown parser
89
+ global.ChatWidget.init = function(userConfig = {}) {
90
+ // Call original init
91
+ originalInit.call(this, userConfig);
92
+
93
+ // Inject enhanced markdown parser
94
+ // We need to override the internal parseMarkdown function
95
+ // This is done by monkey-patching the render cycle
96
+ console.log('[ChatWidget Markdown] Markdown parser enhanced with marked.js');
97
+ };
98
+
99
+ // Expose the enhanced parser for internal use
100
+ // The widget will need to check for this and use it if available
101
+ global.ChatWidget._enhancedMarkdownParser = enhancedParseMarkdown;
102
+
103
+ // Add configuration option
104
+ global.ChatWidget.enableEnhancedMarkdown = function() {
105
+ console.log('[ChatWidget Markdown] Enhanced markdown explicitly enabled');
106
+ return true;
107
+ };
108
+
109
+ })(typeof window !== 'undefined' ? window : this);
110
+
@@ -450,6 +450,77 @@
450
450
  background: rgba(239, 68, 68, 0.1);
451
451
  }
452
452
 
453
+ /* Auto-run controls */
454
+ .cw-autorun-controls {
455
+ padding: 8px 12px;
456
+ display: flex;
457
+ flex-direction: column;
458
+ gap: 8px;
459
+ }
460
+
461
+ .cw-control-label {
462
+ display: flex;
463
+ align-items: center;
464
+ gap: 8px;
465
+ font-size: 13px;
466
+ color: var(--cw-text);
467
+ cursor: pointer;
468
+ padding: 4px;
469
+ border-radius: 4px;
470
+ transition: background 0.15s;
471
+ }
472
+
473
+ .cw-control-label:hover {
474
+ background: var(--cw-bg-muted);
475
+ }
476
+
477
+ .cw-control-label input[type="radio"] {
478
+ margin: 0;
479
+ cursor: pointer;
480
+ }
481
+
482
+ .cw-delay-control {
483
+ padding: 8px 12px;
484
+ }
485
+
486
+ .cw-delay-control input[type="range"] {
487
+ width: 100%;
488
+ margin-top: 4px;
489
+ cursor: pointer;
490
+ }
491
+
492
+ /* Continue button */
493
+ .cw-continue-bar {
494
+ padding: 12px 16px;
495
+ background: var(--cw-bg-muted);
496
+ border-top: 1px solid var(--cw-border);
497
+ display: flex;
498
+ justify-content: center;
499
+ }
500
+
501
+ .cw-continue-btn {
502
+ padding: 10px 20px;
503
+ border: none;
504
+ border-radius: var(--cw-radius-sm);
505
+ background: var(--cw-primary);
506
+ color: white;
507
+ font-size: 14px;
508
+ font-weight: 600;
509
+ cursor: pointer;
510
+ transition: opacity 0.15s;
511
+ display: flex;
512
+ align-items: center;
513
+ gap: 6px;
514
+ }
515
+
516
+ .cw-continue-btn:hover {
517
+ opacity: 0.9;
518
+ }
519
+
520
+ .cw-continue-btn:active {
521
+ opacity: 0.8;
522
+ }
523
+
453
524
  /* Responsive */
454
525
  @media (max-width: 480px) {
455
526
  .cw-widget {
@@ -501,3 +572,118 @@
501
572
  }
502
573
  }
503
574
 
575
+ /* Enhanced Markdown Styles (for chat-widget-markdown.js) */
576
+ .cw-message pre {
577
+ background: var(--cw-bg-muted);
578
+ border: 1px solid var(--cw-border);
579
+ border-radius: var(--cw-radius-sm);
580
+ padding: 12px;
581
+ overflow-x: auto;
582
+ margin: 8px 0;
583
+ font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
584
+ font-size: 13px;
585
+ line-height: 1.4;
586
+ }
587
+
588
+ .cw-message pre code {
589
+ background: none;
590
+ padding: 0;
591
+ border-radius: 0;
592
+ }
593
+
594
+ .cw-message table {
595
+ border-collapse: collapse;
596
+ width: 100%;
597
+ margin: 8px 0;
598
+ font-size: 13px;
599
+ }
600
+
601
+ .cw-message table th,
602
+ .cw-message table td {
603
+ border: 1px solid var(--cw-border);
604
+ padding: 8px 12px;
605
+ text-align: left;
606
+ }
607
+
608
+ .cw-message table th {
609
+ background: var(--cw-bg-muted);
610
+ font-weight: 600;
611
+ }
612
+
613
+ .cw-message table tr:nth-child(even) {
614
+ background: rgba(0, 0, 0, 0.02);
615
+ }
616
+
617
+ .cw-message blockquote {
618
+ border-left: 3px solid var(--cw-primary);
619
+ padding-left: 12px;
620
+ margin: 8px 0;
621
+ color: var(--cw-text-muted);
622
+ font-style: italic;
623
+ }
624
+
625
+ .cw-message h1,
626
+ .cw-message h2,
627
+ .cw-message h3,
628
+ .cw-message h4,
629
+ .cw-message h5,
630
+ .cw-message h6 {
631
+ margin: 12px 0 8px 0;
632
+ font-weight: 600;
633
+ line-height: 1.3;
634
+ }
635
+
636
+ .cw-message h1 { font-size: 1.5em; }
637
+ .cw-message h2 { font-size: 1.3em; }
638
+ .cw-message h3 { font-size: 1.1em; }
639
+ .cw-message h4 { font-size: 1em; }
640
+
641
+ .cw-message hr {
642
+ border: none;
643
+ border-top: 1px solid var(--cw-border);
644
+ margin: 12px 0;
645
+ }
646
+
647
+ .cw-message ul,
648
+ .cw-message ol {
649
+ margin: 8px 0;
650
+ padding-left: 24px;
651
+ }
652
+
653
+ .cw-message li {
654
+ margin: 4px 0;
655
+ }
656
+
657
+ .cw-message p {
658
+ margin: 8px 0;
659
+ }
660
+
661
+ .cw-message p:first-child {
662
+ margin-top: 0;
663
+ }
664
+
665
+ .cw-message p:last-child {
666
+ margin-bottom: 0;
667
+ }
668
+
669
+ /* Dark mode adjustments for enhanced markdown */
670
+ @media (prefers-color-scheme: dark) {
671
+ .cw-message pre {
672
+ background: rgba(255, 255, 255, 0.05);
673
+ border-color: rgba(255, 255, 255, 0.1);
674
+ }
675
+
676
+ .cw-message table th {
677
+ background: rgba(255, 255, 255, 0.05);
678
+ }
679
+
680
+ .cw-message table tr:nth-child(even) {
681
+ background: rgba(255, 255, 255, 0.02);
682
+ }
683
+
684
+ .cw-message table th,
685
+ .cw-message table td {
686
+ border-color: rgba(255, 255, 255, 0.1);
687
+ }
688
+ }
689
+
@@ -43,6 +43,9 @@
43
43
  runEvents: '/api/agent-runtime/runs/{runId}/events/',
44
44
  simulateCustomer: '/api/agent-runtime/simulate-customer/',
45
45
  },
46
+ // Demo flow control
47
+ autoRunDelay: 1000, // Delay in ms before auto-generating next message
48
+ autoRunMode: 'automatic', // 'automatic', 'confirm', or 'manual'
46
49
  };
47
50
 
48
51
  // State
@@ -52,7 +55,8 @@
52
55
  isExpanded: false,
53
56
  isLoading: false,
54
57
  isSimulating: false,
55
- autoRunMode: false,
58
+ autoRunActive: false,
59
+ autoRunPaused: false,
56
60
  debugMode: false,
57
61
  journeyType: 'general',
58
62
  messages: [],
@@ -82,30 +86,35 @@
82
86
  }
83
87
 
84
88
  function parseMarkdown(text) {
85
- // Simple markdown parsing for common patterns
89
+ // Check if enhanced markdown parser is available (from chat-widget-markdown.js)
90
+ if (global.ChatWidget && global.ChatWidget._enhancedMarkdownParser) {
91
+ return global.ChatWidget._enhancedMarkdownParser(text);
92
+ }
93
+
94
+ // Fallback: Simple markdown parsing for common patterns
86
95
  let html = escapeHtml(text);
87
-
96
+
88
97
  // Bold: **text** or __text__
89
98
  html = html.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
90
99
  html = html.replace(/__(.+?)__/g, '<strong>$1</strong>');
91
-
100
+
92
101
  // Italic: *text* or _text_
93
102
  html = html.replace(/\*(.+?)\*/g, '<em>$1</em>');
94
103
  html = html.replace(/_(.+?)_/g, '<em>$1</em>');
95
-
104
+
96
105
  // Code: `code`
97
106
  html = html.replace(/`(.+?)`/g, '<code>$1</code>');
98
-
107
+
99
108
  // Links: [text](url)
100
109
  html = html.replace(/\[(.+?)\]\((.+?)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
101
-
110
+
102
111
  // Line breaks
103
112
  html = html.replace(/\n/g, '<br>');
104
-
113
+
105
114
  // Lists: - item or * item
106
115
  html = html.replace(/^[\-\*]\s+(.+)$/gm, '<li>$1</li>');
107
116
  html = html.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
108
-
117
+
109
118
  return html;
110
119
  }
111
120
 
@@ -339,8 +348,13 @@
339
348
  render();
340
349
 
341
350
  // Trigger auto-run if enabled
342
- if (state.autoRunMode && !state.error) {
343
- setTimeout(() => triggerAutoRun(), 1000);
351
+ if (state.autoRunActive && !state.error) {
352
+ if (config.autoRunMode === 'automatic') {
353
+ setTimeout(() => triggerAutoRun(), config.autoRunDelay);
354
+ } else if (config.autoRunMode === 'confirm') {
355
+ state.autoRunPaused = true;
356
+ render();
357
+ }
344
358
  }
345
359
  };
346
360
 
@@ -365,12 +379,13 @@
365
379
  // ============================================================================
366
380
 
367
381
  async function triggerAutoRun() {
368
- if (!state.autoRunMode || state.isLoading || state.isSimulating) return;
382
+ if (!state.autoRunActive || state.isLoading || state.isSimulating) return;
369
383
 
370
384
  const lastMessage = state.messages[state.messages.length - 1];
371
385
  if (lastMessage?.role !== 'assistant') return;
372
386
 
373
387
  state.isSimulating = true;
388
+ state.autoRunPaused = false;
374
389
  render();
375
390
 
376
391
  try {
@@ -402,7 +417,8 @@
402
417
  async function startDemoFlow(journeyType) {
403
418
  clearMessages();
404
419
  state.journeyType = journeyType;
405
- state.autoRunMode = true;
420
+ state.autoRunActive = true;
421
+ state.autoRunPaused = false;
406
422
  render();
407
423
 
408
424
  const journey = config.journeyTypes[journeyType];
@@ -419,7 +435,26 @@
419
435
  }
420
436
 
421
437
  function stopAutoRun() {
422
- state.autoRunMode = false;
438
+ state.autoRunActive = false;
439
+ state.autoRunPaused = false;
440
+ render();
441
+ }
442
+
443
+ function continueAutoRun() {
444
+ if (state.autoRunActive && state.autoRunPaused) {
445
+ triggerAutoRun();
446
+ }
447
+ }
448
+
449
+ function setAutoRunMode(mode) {
450
+ if (['automatic', 'confirm', 'manual'].includes(mode)) {
451
+ config.autoRunMode = mode;
452
+ render();
453
+ }
454
+ }
455
+
456
+ function setAutoRunDelay(delay) {
457
+ config.autoRunDelay = Math.max(0, parseInt(delay) || 1000);
423
458
  render();
424
459
  }
425
460
 
@@ -435,7 +470,8 @@
435
470
 
436
471
  function closeWidget() {
437
472
  state.isOpen = false;
438
- state.autoRunMode = false;
473
+ state.autoRunActive = false;
474
+ state.autoRunPaused = false;
439
475
  render();
440
476
  }
441
477
 
@@ -453,7 +489,8 @@
453
489
  state.messages = [];
454
490
  state.conversationId = null;
455
491
  state.error = null;
456
- state.autoRunMode = false;
492
+ state.autoRunActive = false;
493
+ state.autoRunPaused = false;
457
494
  setStoredValue(config.conversationIdKey, null);
458
495
  render();
459
496
  }
@@ -504,16 +541,48 @@
504
541
  </button>
505
542
  `).join('');
506
543
 
507
- const stopButton = state.autoRunMode ? `
544
+ const controlsSection = state.autoRunActive ? `
545
+ <div class="cw-dropdown-separator"></div>
546
+ <div class="cw-dropdown-label">Demo Controls</div>
547
+ <div class="cw-autorun-controls">
548
+ <label class="cw-control-label">
549
+ <input type="radio" name="autorun-mode" value="automatic"
550
+ ${config.autoRunMode === 'automatic' ? 'checked' : ''}
551
+ onchange="ChatWidget.setAutoRunMode('automatic')">
552
+ <span>⚡ Automatic</span>
553
+ </label>
554
+ <label class="cw-control-label">
555
+ <input type="radio" name="autorun-mode" value="confirm"
556
+ ${config.autoRunMode === 'confirm' ? 'checked' : ''}
557
+ onchange="ChatWidget.setAutoRunMode('confirm')">
558
+ <span>👆 Confirm Next</span>
559
+ </label>
560
+ <label class="cw-control-label">
561
+ <input type="radio" name="autorun-mode" value="manual"
562
+ ${config.autoRunMode === 'manual' ? 'checked' : ''}
563
+ onchange="ChatWidget.setAutoRunMode('manual')">
564
+ <span>✋ Manual</span>
565
+ </label>
566
+ </div>
567
+ ${config.autoRunMode === 'automatic' ? `
568
+ <div class="cw-delay-control">
569
+ <label class="cw-control-label">
570
+ <span>Delay: ${config.autoRunDelay}ms</span>
571
+ <input type="range" min="0" max="5000" step="100"
572
+ value="${config.autoRunDelay}"
573
+ oninput="ChatWidget.setAutoRunDelay(this.value)">
574
+ </label>
575
+ </div>
576
+ ` : ''}
508
577
  <div class="cw-dropdown-separator"></div>
509
578
  <button class="cw-dropdown-item cw-dropdown-item-danger" data-action="stop-autorun">
510
- âšī¸ Stop Auto-Run
579
+ âšī¸ Stop Demo
511
580
  </button>
512
581
  ` : '';
513
582
 
514
583
  return `
515
584
  <div class="cw-dropdown">
516
- <button class="cw-header-btn ${state.autoRunMode ? 'cw-btn-active' : ''}"
585
+ <button class="cw-header-btn ${state.autoRunActive ? 'cw-btn-active' : ''}"
517
586
  data-action="toggle-journey-dropdown"
518
587
  title="Demo Flows"
519
588
  ${state.isLoading || state.isSimulating ? 'disabled' : ''}>
@@ -523,7 +592,7 @@
523
592
  <div class="cw-dropdown-label">Demo Flows</div>
524
593
  <div class="cw-dropdown-separator"></div>
525
594
  ${journeyItems}
526
- ${stopButton}
595
+ ${controlsSection}
527
596
  </div>
528
597
  </div>
529
598
  `;
@@ -567,9 +636,17 @@
567
636
  </div>
568
637
  ` : '';
569
638
 
570
- const statusBar = (state.autoRunMode || state.debugMode) ? `
639
+ const continueButton = (state.autoRunActive && state.autoRunPaused && config.autoRunMode === 'confirm') ? `
640
+ <div class="cw-continue-bar">
641
+ <button class="cw-continue-btn" data-action="continue-autorun" style="background-color: ${config.primaryColor}">
642
+ â–ļī¸ Continue Demo
643
+ </button>
644
+ </div>
645
+ ` : '';
646
+
647
+ const statusBar = (state.autoRunActive || state.debugMode) ? `
571
648
  <div class="cw-status-bar">
572
- ${state.autoRunMode ? `<span>🤖 Auto-run: ${config.journeyTypes[state.journeyType]?.label || state.journeyType}</span>` : ''}
649
+ ${state.autoRunActive ? `<span>🤖 Demo: ${config.journeyTypes[state.journeyType]?.label || state.journeyType} (${config.autoRunMode})</span>` : ''}
573
650
  ${state.debugMode ? '<span>🐛 Debug</span>' : ''}
574
651
  </div>
575
652
  ` : '';
@@ -611,6 +688,7 @@
611
688
  ${messagesHtml}
612
689
  ${typingIndicator}
613
690
  </div>
691
+ ${continueButton}
614
692
  ${errorBar}
615
693
  <form class="cw-input-form" id="cw-input-form">
616
694
  <input type="text" class="cw-input" placeholder="${escapeHtml(config.placeholder)}" ${state.isLoading ? 'disabled' : ''}>
@@ -645,6 +723,7 @@
645
723
  case 'toggle-debug': toggleDebugMode(); break;
646
724
  case 'clear': clearMessages(); break;
647
725
  case 'stop-autorun': stopAutoRun(); break;
726
+ case 'continue-autorun': continueAutoRun(); break;
648
727
  case 'toggle-journey-dropdown':
649
728
  const dropdown = document.getElementById('cw-journey-dropdown');
650
729
  if (dropdown) {
@@ -756,6 +835,9 @@
756
835
  clearMessages,
757
836
  startDemoFlow,
758
837
  stopAutoRun,
838
+ continueAutoRun,
839
+ setAutoRunMode,
840
+ setAutoRunDelay,
759
841
  getState: () => ({ ...state }),
760
842
  getConfig: () => ({ ...config }),
761
843
  };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@makemore/agent-frontend",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
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": [
7
7
  "dist/chat-widget.js",
8
8
  "dist/chat-widget.css",
9
+ "dist/chat-widget-markdown.js",
9
10
  "README.md",
10
11
  "LICENSE"
11
12
  ],