@makemore/agent-frontend 1.7.1 → 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 CHANGED
@@ -1,11 +1,10 @@
1
1
  # Agent Frontend
2
2
 
3
- A standalone, zero-dependency chat widget for AI agents. Embed conversational AI into any website with a single script tag.
3
+ A lightweight chat widget for AI agents built with Preact. Embed conversational AI into any website with a single script tag.
4
4
 
5
5
  <p align="center">
6
- <img src="https://img.shields.io/badge/vanilla-JavaScript-yellow" alt="Vanilla JS">
7
- <img src="https://img.shields.io/badge/size-~15kb-green" alt="Size">
8
- <img src="https://img.shields.io/badge/dependencies-0-blue" alt="Zero Dependencies">
6
+ <img src="https://img.shields.io/badge/Preact-673AB8?logo=preact&logoColor=white" alt="Preact">
7
+ <img src="https://img.shields.io/badge/size-~25kb-green" alt="Size">
9
8
  <img src="https://img.shields.io/badge/license-MIT-purple" alt="MIT License">
10
9
  </p>
11
10
 
@@ -13,10 +12,11 @@ A standalone, zero-dependency chat widget for AI agents. Embed conversational AI
13
12
 
14
13
  Most chat widgets are tightly coupled to specific frameworks or require complex build setups. Agent Frontend is different:
15
14
 
16
- - **Zero dependencies** - Pure vanilla JavaScript, no React/Vue/Angular required
15
+ - **Lightweight** - Built with Preact (~3kb) for minimal bundle size
17
16
  - **CSS isolated** - Won't conflict with your existing styles (uses `all: initial` reset)
18
17
  - **SSE streaming** - Real-time token-by-token responses, not polling
19
18
  - **Production ready** - Session management, error handling, conversation persistence
19
+ - **Component-based** - Clean architecture with hooks for state management
20
20
 
21
21
  ## Features
22
22
 
@@ -174,7 +174,126 @@ 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
+ | `showConversationSidebar` | boolean | `true` | Show conversation history sidebar with hamburger menu |
177
178
  | `onEvent` | function | `null` | Callback for SSE events: `(eventType, payload) => void` |
179
+ | `authStrategy` | string | `null` | Auth strategy: `'token'`, `'jwt'`, `'session'`, `'anonymous'`, `'none'` (auto-detected if null) |
180
+ | `authToken` | string | `null` | Token value for `'token'` or `'jwt'` strategies |
181
+ | `authHeader` | string | `null` | Custom header name (defaults based on strategy) |
182
+ | `authTokenPrefix` | string | `null` | Custom token prefix (defaults based on strategy) |
183
+ | `anonymousSessionEndpoint` | string | `null` | Endpoint for anonymous session (defaults to `apiPaths.anonymousSession`) |
184
+ | `anonymousTokenKey` | string | `'chat_widget_anonymous_token'` | localStorage key for anonymous token |
185
+ | `onAuthError` | function | `null` | Callback for auth errors: `(error) => void` |
186
+
187
+ ### Authentication
188
+
189
+ The widget supports multiple authentication strategies with sensible defaults:
190
+
191
+ #### Token Authentication (Django REST Framework)
192
+
193
+ ```javascript
194
+ ChatWidget.init({
195
+ backendUrl: 'https://api.example.com',
196
+ agentKey: 'my-agent',
197
+ authStrategy: 'token',
198
+ authToken: 'abc123...',
199
+ // Sends: Authorization: Token abc123...
200
+ });
201
+ ```
202
+
203
+ #### JWT/Bearer Authentication
204
+
205
+ ```javascript
206
+ ChatWidget.init({
207
+ backendUrl: 'https://api.example.com',
208
+ agentKey: 'my-agent',
209
+ authStrategy: 'jwt',
210
+ authToken: 'eyJ...',
211
+ // Sends: Authorization: Bearer eyJ...
212
+ });
213
+ ```
214
+
215
+ #### Session-Based Authentication (Cookies)
216
+
217
+ ```javascript
218
+ ChatWidget.init({
219
+ backendUrl: 'https://api.example.com',
220
+ agentKey: 'my-agent',
221
+ authStrategy: 'session',
222
+ // Sends requests with credentials: 'include'
223
+ // No auth header, relies on session cookie
224
+ });
225
+ ```
226
+
227
+ #### Anonymous Session Tokens
228
+
229
+ ```javascript
230
+ ChatWidget.init({
231
+ backendUrl: 'https://api.example.com',
232
+ agentKey: 'my-agent',
233
+ authStrategy: 'anonymous',
234
+ anonymousSessionEndpoint: '/api/accounts/anonymous-session/',
235
+ // On first request: fetches anonymous token from endpoint
236
+ // Persists token to localStorage
237
+ // Sends: X-Anonymous-Token: {token}
238
+ });
239
+ ```
240
+
241
+ #### No Authentication (Public Endpoints)
242
+
243
+ ```javascript
244
+ ChatWidget.init({
245
+ backendUrl: 'https://api.example.com',
246
+ agentKey: 'my-agent',
247
+ authStrategy: 'none',
248
+ // No auth headers sent
249
+ });
250
+ ```
251
+
252
+ #### Custom Headers and Prefixes
253
+
254
+ ```javascript
255
+ ChatWidget.init({
256
+ authStrategy: 'token',
257
+ authToken: 'mytoken123',
258
+ authHeader: 'X-API-Key', // Custom header name
259
+ authTokenPrefix: '', // No prefix (just the token)
260
+ // Sends: X-API-Key: mytoken123
261
+ });
262
+ ```
263
+
264
+ #### Dynamic Token Updates
265
+
266
+ Update authentication after initialization (e.g., after user login):
267
+
268
+ ```javascript
269
+ // After user logs in
270
+ ChatWidget.setAuth({
271
+ strategy: 'jwt',
272
+ token: 'new-jwt-token-after-login'
273
+ });
274
+
275
+ // After user logs out
276
+ ChatWidget.clearAuth();
277
+
278
+ // Handle token refresh on auth errors
279
+ ChatWidget.init({
280
+ authStrategy: 'jwt',
281
+ authToken: initialToken,
282
+ onAuthError: async (error) => {
283
+ if (error.status === 401) {
284
+ const newToken = await refreshToken();
285
+ ChatWidget.setAuth({ token: newToken });
286
+ }
287
+ }
288
+ });
289
+ ```
290
+
291
+ #### Auto-Detection
292
+
293
+ If no `authStrategy` is specified, the widget auto-detects based on config:
294
+ - If `authToken` is provided → uses `'token'` strategy
295
+ - If `anonymousSessionEndpoint` or `apiPaths.anonymousSession` is configured → uses `'anonymous'` strategy
296
+ - Otherwise → uses `'none'`
178
297
 
179
298
  ### Event Callback
180
299
 
@@ -456,6 +575,12 @@ ChatWidget.send('Hello, I need help!');
456
575
  // Clear the conversation
457
576
  ChatWidget.clearMessages();
458
577
 
578
+ // Conversation sidebar controls
579
+ ChatWidget.toggleSidebar(); // Open/close conversation sidebar
580
+ ChatWidget.newConversation(); // Start a new conversation
581
+ ChatWidget.switchConversation('conversation-id'); // Switch to a specific conversation
582
+ ChatWidget.loadMoreMessages(); // Load older messages
583
+
459
584
  // Text-to-speech controls
460
585
  ChatWidget.toggleTTS(); // Toggle TTS on/off
461
586
  ChatWidget.stopSpeech(); // Stop current speech and clear queue
@@ -477,6 +602,10 @@ ChatWidget.setAutoRunMode('automatic'); // 'automatic', 'confirm', or 'manual'
477
602
  // Change auto-run delay (in milliseconds)
478
603
  ChatWidget.setAutoRunDelay(2000);
479
604
 
605
+ // Authentication methods
606
+ ChatWidget.setAuth({ strategy: 'jwt', token: 'new-token' }); // Update auth
607
+ ChatWidget.clearAuth(); // Clear authentication
608
+
480
609
  // Remove the widget from the page
481
610
  ChatWidget.destroy();
482
611
 
@@ -606,9 +735,135 @@ agent-frontend/
606
735
 
607
736
  Requires: `EventSource` (SSE), `fetch`, `localStorage`
608
737
 
738
+ ## Multiple Instances
739
+
740
+ You can create multiple independent chat widgets on the same page using `createInstance()`:
741
+
742
+ ### Basic Multi-Instance Setup
743
+
744
+ ```html
745
+ <div id="chat-1" style="width: 400px; height: 500px;"></div>
746
+ <div id="chat-2" style="width: 400px; height: 500px;"></div>
747
+
748
+ <script>
749
+ // Create first widget
750
+ const widget1 = ChatWidget.createInstance({
751
+ containerId: 'chat-1',
752
+ backendUrl: 'https://your-api.com',
753
+ agentKey: 'support-agent',
754
+ title: 'Support Chat',
755
+ primaryColor: '#0066cc',
756
+ embedded: true,
757
+ });
758
+
759
+ // Create second widget
760
+ const widget2 = ChatWidget.createInstance({
761
+ containerId: 'chat-2',
762
+ backendUrl: 'https://your-api.com',
763
+ agentKey: 'sales-agent',
764
+ title: 'Sales Chat',
765
+ primaryColor: '#00cc66',
766
+ embedded: true,
767
+ });
768
+ </script>
769
+ ```
770
+
771
+ ### Instance Configuration Options
772
+
773
+ | Option | Type | Default | Description |
774
+ |--------|------|---------|-------------|
775
+ | `containerId` | string | `null` | ID of the container element for embedded mode |
776
+ | `embedded` | boolean | `false` | If true, renders inline in container instead of floating |
777
+ | `metadata` | object | `{}` | Custom metadata to send with each request |
778
+
779
+ ### Instance Methods
780
+
781
+ Each instance returned by `createInstance()` has its own methods:
782
+
783
+ ```javascript
784
+ const widget = ChatWidget.createInstance({ ... });
785
+
786
+ // Control the widget
787
+ widget.open();
788
+ widget.close();
789
+ widget.send('Hello!');
790
+ widget.clearMessages();
791
+
792
+ // TTS controls
793
+ widget.toggleTTS();
794
+ widget.stopSpeech();
795
+
796
+ // Authentication
797
+ widget.setAuth({ strategy: 'jwt', token: 'new-token' });
798
+ widget.clearAuth();
799
+
800
+ // Get state/config
801
+ const state = widget.getState();
802
+ const config = widget.getConfig();
803
+
804
+ // Destroy the widget
805
+ widget.destroy();
806
+ ```
807
+
808
+ ### Managing Multiple Instances
809
+
810
+ ```javascript
811
+ // Get a specific instance by ID
812
+ const widget = ChatWidget.getInstance('cw-1');
813
+
814
+ // Get all instances
815
+ const allWidgets = ChatWidget.getAllInstances();
816
+
817
+ // Destroy all instances
818
+ ChatWidget.getAllInstances().forEach(w => w.destroy());
819
+ ```
820
+
821
+ ### Embedded vs Floating Mode
822
+
823
+ **Embedded Mode** (`embedded: true`):
824
+ - Widget renders inside the specified container
825
+ - No floating button or close button
826
+ - Widget is always visible
827
+ - Perfect for split-pane layouts, dashboards, or dedicated chat pages
828
+
829
+ **Floating Mode** (`embedded: false`, default):
830
+ - Widget appears as a floating button in the corner
831
+ - Clicking opens the chat panel
832
+ - Has close and expand buttons
833
+ - Traditional chat widget behavior
834
+
835
+ ### Storage Isolation
836
+
837
+ Each embedded instance uses isolated localStorage keys based on `containerId`:
838
+ - `chat_widget_conversation_id_chat-1` for widget in `#chat-1`
839
+ - `chat_widget_conversation_id_chat-2` for widget in `#chat-2`
840
+
841
+ This ensures conversations don't get mixed up between instances.
842
+
609
843
  ## Version History
610
844
 
611
- ### v1.4.0 (Latest)
845
+ ### v2.0.0 (Latest)
846
+ - 🔄 **Preact Rewrite**: Complete rewrite using Preact for better maintainability
847
+ - 🧩 **Component Architecture**: Modular components (ChatWidget, Header, InputForm, Message, MessageList, Sidebar)
848
+ - 🪝 **React-style Hooks**: useChat and useModels hooks for state management
849
+ - 🎛️ **Model Selector**: Built-in model selection dropdown
850
+ - 📦 **Smaller Bundle**: Optimized build with esbuild
851
+ - 🔧 **Better Developer Experience**: Watch mode, source maps, cleaner code structure
852
+
853
+ ### v1.10.1
854
+ - 📚 **Conversation Sidebar**: Browse and switch between past conversations via hamburger menu
855
+ - 📜 **Message Pagination**: Load older messages with "load more" functionality
856
+ - 🔐 **CSRF Support**: Automatic CSRF token handling for Django session auth
857
+ - ➕ **New Conversation**: Start fresh conversations from the sidebar
858
+ - 🔄 **Auto-restore**: Automatically loads messages when returning to a conversation
859
+
860
+ ### v1.5.0
861
+ - 🔀 **Multiple Instances**: Create multiple independent chat widgets on the same page
862
+ - 📦 **Embedded Mode**: Render widgets inline in containers for dashboards and split-pane layouts
863
+ - 🔒 **Storage Isolation**: Each instance has isolated localStorage for conversations
864
+ - 🎯 **Instance API**: Full control over individual widget instances
865
+
866
+ ### v1.4.0
612
867
  - ✨ **Text-to-Speech**: ElevenLabs integration with secure Django proxy support
613
868
  - 🔊 Automatic speech for assistant and simulated user messages
614
869
  - 🎛️ Smart speech queuing to prevent overlap
@@ -638,4 +893,4 @@ Requires: `EventSource` (SSE), `fetch`, `localStorage`
638
893
 
639
894
  ## License
640
895
 
641
- MIT © 2024
896
+ MIT © 2025