diff --git a/docs/HTML_EXTENSIONS.md b/docs/HTML_EXTENSIONS.md new file mode 100644 index 0000000..9bf5be0 --- /dev/null +++ b/docs/HTML_EXTENSIONS.md @@ -0,0 +1,445 @@ +# 🎨 HTML/Frontend Extensions Architecture + +## Overview +This document defines the **client-side extension system** for Chat Switchboard. Extensions are HTML/JS/CSS modules that can hook into the application lifecycle, add UI elements, intercept messages, and extend functionality. + +--- + +## 🔌 Extension Interface + +### Extension Manifest Structure +```javascript +{ + "id": "example-extension", + "name": "Example Extension", + "version": "1.0.0", + "author": "Your Name", + "description": "Does something cool", + "type": "frontend", // or "hybrid" if it has backend components + "permissions": ["ui", "messages", "storage"], + "entrypoint": "extension.js", + "styles": "extension.css", + "hooks": { + "onLoad": true, + "onMessageSend": true, + "onMessageReceive": true, + "onModelSwitch": true + }, + "ui": { + "toolbar": true, + "sidebar": false, + "settings": true + } +} +``` + +--- + +## 📦 Extension API + +### Core Extension Class +```javascript +class ChatSwitchboardExtension { + constructor(manifest) { + this.manifest = manifest; + this.enabled = true; + } + + // Lifecycle hooks + onLoad() {} + onUnload() {} + onEnable() {} + onDisable() {} + + // Message hooks + async onMessageSend(message, context) { + // Modify message before sending + // return modified message or null to cancel + return message; + } + + async onMessageReceive(message, context) { + // Process received message + // return modified message or original + return message; + } + + async onMessageDisplay(message, element) { + // Modify message DOM before display + return element; + } + + // UI hooks + onModelSwitch(oldModel, newModel) {} + onChatSwitch(oldChatId, newChatId) {} + onSettingsOpen() {} + + // Render hooks + renderToolbarButton() { + // Return HTML string or DOM element + return null; + } + + renderSidebarPanel() { + return null; + } + + renderSettingsPanel() { + return null; + } + + renderMessageAction(message) { + // Add custom actions to message bubbles + return null; + } +} +``` + +--- + +## 🎯 Extension Categories + +### 1. **UI Extensions** +Add visual elements and interface enhancements. + +**Examples:** +- Syntax highlighter themes +- Message templates/snippets +- Custom emoji pickers +- Voice input buttons +- Image/file attachments + +**Hooks:** `renderToolbarButton`, `renderSidebarPanel`, `renderMessageAction` + +--- + +### 2. **Message Processors** +Transform messages before/after sending. + +**Examples:** +- Markdown preprocessor +- Code formatter +- Translation layer +- Prompt templates +- Token counter + +**Hooks:** `onMessageSend`, `onMessageReceive`, `onMessageDisplay` + +--- + +### 3. **Model Extensions** +Enhance model selection and routing. + +**Examples:** +- Model performance stats +- Cost calculator +- Context window manager +- Model recommendation engine +- Fallback routing (if model fails, try another) + +**Hooks:** `onModelSwitch`, access to `State.settings.model` + +--- + +### 4. **Storage Extensions** +Extend data persistence capabilities. + +**Examples:** +- Cloud sync (S3, Dropbox) +- Export formats (PDF, DOCX) +- Search indexing +- Tagging system +- Chat organization + +**Permissions:** `storage` + +--- + +### 5. **Tool/Function Extensions** +Enable LLM function calling (critical for your use case). + +**Examples:** +- Web search tool +- Calculator +- Code execution sandbox +- API caller +- File system access + +**Hooks:** `onFunctionCall`, `registerFunction` + +--- + +## 🛠️ Extension Manager + +### Core API +```javascript +// Global extension registry +window.ExtensionManager = { + extensions: new Map(), + + // Register an extension + register(manifest, ExtensionClass) { + const ext = new ExtensionClass(manifest); + this.extensions.set(manifest.id, ext); + ext.onLoad(); + return ext; + }, + + // Enable/disable + enable(id) {}, + disable(id) {}, + unload(id) {}, + + // Hook execution + async executeHook(hookName, ...args) { + const results = []; + for (const [id, ext] of this.extensions) { + if (ext.enabled && ext[hookName]) { + const result = await ext[hookName](...args); + results.push({ id, result }); + } + } + return results; + }, + + // Get all extensions with specific capability + getByPermission(permission) { + return Array.from(this.extensions.values()) + .filter(ext => ext.manifest.permissions.includes(permission)); + } +}; +``` + +--- + +## 📂 Extension File Structure + +``` +extensions/ +├── example-extension/ +│ ├── manifest.json +│ ├── extension.js +│ ├── extension.css (optional) +│ ├── README.md +│ └── assets/ +│ └── icon.svg +``` + +### Loading Extensions +```javascript +async function loadExtension(path) { + const manifest = await fetch(`${path}/manifest.json`).then(r => r.json()); + + // Load JS + const module = await import(`${path}/${manifest.entrypoint}`); + + // Load CSS if present + if (manifest.styles) { + const link = document.createElement('link'); + link.rel = 'stylesheet'; + link.href = `${path}/${manifest.styles}`; + document.head.appendChild(link); + } + + // Register + ExtensionManager.register(manifest, module.default); +} +``` + +--- + +## 🔐 Security & Permissions + +### Permission System +```javascript +const PERMISSIONS = { + ui: "Modify user interface", + messages: "Read and modify messages", + storage: "Access local storage", + network: "Make network requests", + settings: "Access user settings", + clipboard: "Access clipboard", + notifications: "Show notifications" +}; +``` + +### Sandboxing (Future) +- Use iframes for untrusted extensions +- Content Security Policy restrictions +- API key scoping (extensions can't access main API key) + +--- + +## 🎨 Example Extensions + +### 1. Token Counter +```javascript +class TokenCounterExtension extends ChatSwitchboardExtension { + onLoad() { + this.tokenCount = 0; + } + + renderToolbarButton() { + return ` + + `; + } + + async onMessageSend(message, context) { + // Rough estimation: 1 token ≈ 4 chars + this.tokenCount = Math.ceil(message.content.length / 4); + document.getElementById('tokenCount').textContent = this.tokenCount; + return message; + } +} +``` + +### 2. Code Formatter +```javascript +class CodeFormatterExtension extends ChatSwitchboardExtension { + async onMessageDisplay(message, element) { + if (message.role === 'assistant') { + // Find code blocks and apply Prism.js highlighting + element.querySelectorAll('pre code').forEach(block => { + Prism.highlightElement(block); + }); + } + return element; + } + + renderMessageAction(message) { + if (message.content.includes('```')) { + return ` + + `; + } + return null; + } +} +``` + +### 3. Model Router (Smart Fallback) +```javascript +class ModelRouterExtension extends ChatSwitchboardExtension { + async onMessageSend(message, context) { + // If message is long, use high-context model + if (message.content.length > 5000) { + const originalModel = State.settings.model; + State.settings.model = 'claude-3-opus-20240229'; // High context + + // Restore after response + context.onComplete = () => { + State.settings.model = originalModel; + }; + } + return message; + } +} +``` + +--- + +## 🚀 Integration with App + +### Modify `app.js` to support hooks: +```javascript +async function sendMessage() { + // ... existing code ... + + // Execute hook before sending + const hookResults = await ExtensionManager.executeHook( + 'onMessageSend', + message, + { chatId: State.currentChatId } + ); + + // Check if any extension cancelled the send + if (hookResults.some(r => r.result === null)) { + return; + } + + // Apply transformations + for (const { result } of hookResults) { + if (result && result !== message) { + message = result; + } + } + + // ... continue with API call ... +} +``` + +--- + +## 📋 Extension Discovery + +### Extension Store (Future) +```javascript +{ + "extensions": [ + { + "id": "web-search", + "name": "Web Search Tool", + "description": "Adds web search capability via function calling", + "author": "Chat Switchboard Team", + "version": "1.0.0", + "downloadUrl": "https://extensions.switchboard/web-search.zip", + "verified": true, + "rating": 4.8, + "downloads": 1250 + } + ] +} +``` + +--- + +## 🎯 Next Steps + +1. **Implement ExtensionManager** in `src/js/extensions.js` +2. **Add hook points** to existing code (app.js, ui.js, api.js) +3. **Create example extensions** to validate API +4. **Build extension settings UI** for enable/disable/configure +5. **Document extension development** with starter template + +--- + +## 🤝 Extension Development Workflow + +```bash +# Create new extension +mkdir extensions/my-extension +cd extensions/my-extension + +# Generate manifest +cat > manifest.json << EOF +{ + "id": "my-extension", + "name": "My Extension", + "version": "1.0.0", + "entrypoint": "extension.js", + "permissions": ["messages"] +} +EOF + +# Create extension class +cat > extension.js << EOF +class MyExtension extends ChatSwitchboardExtension { + onLoad() { + console.log('My extension loaded!'); + } +} +export default MyExtension; +EOF + +# Test in dev mode +# Extensions auto-load from /extensions/ directory +``` + +--- + +**This architecture makes Chat Switchboard infinitely extensible while keeping the core lean.** \ No newline at end of file